[
  {
    "path": ".gitignore",
    "content": ".idea\ncomposer.lock\n*.log\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\n\nlanguage: php\n\nbranches:\n  only:\n    - stable\n\ncache:\n  directories:\n    - $HOME/.composer/cache\n\nbefore_install:\n  - composer self-update\n\ninstall:\n  - composer install --no-dev --no-interaction --ignore-platform-reqs\n  - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .\n  - composer require --update-no-dev --no-interaction \"topthink/think-image:^1.0\"\n  - composer require --update-no-dev --no-interaction \"topthink/think-migration:^1.0\"\n  - composer require --update-no-dev --no-interaction \"topthink/think-captcha:^1.0\"\n  - composer require --update-no-dev --no-interaction \"topthink/think-mongo:^1.0\"\n  - composer require --update-no-dev --no-interaction \"topthink/think-worker:^1.0\"\n  - composer require --update-no-dev --no-interaction \"topthink/think-helper:^1.0\"\n  - composer require --update-no-dev --no-interaction \"topthink/think-queue:^1.0\"\n  - composer require --update-no-dev --no-interaction \"topthink/think-angular:^1.0\"\n  - composer require --dev --update-no-dev --no-interaction \"topthink/think-testing:^1.0\"\n  - zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .\n\nscript:\n  - php think unit\n\ndeploy:\n  provider: releases\n  api_key:\n    secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=\n  file:\n    - ThinkPHP_Core.zip\n    - ThinkPHP_Full.zip\n  skip_cleanup: true\n  on:\n    tags: true\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\nThinkPHP遵循Apache2开源协议发布，并提供免费使用。\n版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)\nAll rights reserved。\nThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。\n\nApache Licence是著名的非盈利开源组织Apache采用的协议。\n该协议和BSD类似，鼓励代码共享和尊重原作者的著作权，\n允许代码修改，再作为开源或商业软件发布。需要满足\n的条件： \n1． 需要给代码的用户一份Apache Licence ；\n2． 如果你修改了代码，需要在被修改的文件中说明；\n3． 在延伸的代码中（修改和有源代码衍生的代码中）需要\n带有原来代码中的协议，商标，专利声明和其他原来作者规\n定需要包含的说明；\n4． 如果再发布的产品中包含一个Notice文件，则在Notice文\n件中需要带有本协议内容。你可以在Notice中增加自己的\n许可，但不可以表现为对Apache Licence构成更改。 \n具体的协议参考：http://www.apache.org/licenses/LICENSE-2.0\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\nFOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\nCOPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\nBUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\nANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# 简介\n本项目是采用PHP语言,THINKPHP5.0框架开发的全栈应用系统。在开发这个项目时，微信还没有OFO微信小程序，又不想下载APP去使用,只能在支付宝上面使用OFO，偶然间发现某人写了一个关于OFO的微信小程序，链接如下：给ofo小黄车撸一个微信小程序，数据是模拟的，没有数据库，没有后台，所以我基于这个前端项目，设计了数据库，提供了数据支持和后台服务。\n\n# 项目截图\n\n ![](http://upload-images.jianshu.io/upload_images/7689038-204c44614dd8bf7c.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n**体验版页面**\n\n![](http://upload-images.jianshu.io/upload_images/7689038-b00b7339239bd47b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n**支付页面**\n\n![](http://upload-images.jianshu.io/upload_images/7689038-03862c0407a00ef6.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n**首页页面**\n\n![](http://upload-images.jianshu.io/upload_images/7689038-33691fe2e959a2fb.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n**用车页面**\n\n![](http://upload-images.jianshu.io/upload_images/7689038-247c015e3ed60e72.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n**开锁页面**\n\n![](http://upload-images.jianshu.io/upload_images/7689038-c0ea09c81011ce01.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n**开锁页面**\n\n![](http://upload-images.jianshu.io/upload_images/7689038-4394c16405be2809.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n**计费页面**\n\n![](http://upload-images.jianshu.io/upload_images/7689038-825913386dc0a444.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n**充值页面**\n\n![](http://upload-images.jianshu.io/upload_images/7689038-1bfd8c5205e53511.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n**个人中心页面**\n\n![](http://upload-images.jianshu.io/upload_images/7689038-7e97f9701caf318c.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n**我的钱包页面**\n\n\n\n\n# ofo小程序的架构体系：\n![](http://upload-images.jianshu.io/upload_images/7689038-0639fb41282825fc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/600)\n\n# 小程序数据从服务器到前端交互总结：\n![](http://upload-images.jianshu.io/upload_images/7689038-df002d6a6923605a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/600)\n\n# 数据库设计：\n**用户表：**\n```\n**user  | CREATE TABLE `user` (**\n`id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n`openid` varchar(50) NOT NULL COMMENT '用户的唯一标识',\n`create_time` int(11) DEFAULT NULL,\n`delete_time` int(11) DEFAULT NULL,\n`balance` decimal(60,2) NOT NULL COMMENT '余额',\n`guarantee` decimal(60,2) NOT NULL COMMENT '保证金',\n`update_time` int(11) DEFAULT NULL,\nPRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 |\n```\n\n**小黄车表：**\n```\n**| bike  | CREATE TABLE `bike` (**\n`id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n`latitude` float(11,6) NOT NULL COMMENT '经度',\n`is_show` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0未使用 1使用',\n`longitude` float(11,6) NOT NULL COMMENT '纬度',\n`password` int(11) NOT NULL COMMENT '单车密码',\n`type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0正常，1故障',\n`create_time` int(11) NOT NULL,\n`update_time` int(11) NOT NULL,\nPRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 |\n```\n\n**故障分类表：**\n```\n**| trouble_cate | CREATE TABLE `trouble_cate` (**\n`id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n`name` varchar(20) NOT NULL COMMENT '故障名称',\n`create_time` int(11) DEFAULT NULL,\n`update_time` int(11) DEFAULT NULL,\nPRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 |\n```\n\n**故障记录表：**\n```\n**| trouble_record | CREATE TABLE `trouble_record` (**\n`id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n`user_id` int(11) NOT NULL COMMENT '用户ID',\n`bike_id` int(11) DEFAULT NULL COMMENT '单车ID',\n`longitude` varchar(50) NOT NULL COMMENT '经度',\n`latitude` varchar(50) NOT NULL COMMENT '纬度',\n`img` varchar(50) DEFAULT NULL COMMENT '上传的图片',\n`remark` varchar(50) DEFAULT NULL COMMENT '备注',\n`create_time` int(11) NOT NULL,\n`update_time` int(11) NOT NULL,\nPRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 |\n```\n**充值表：**\n```\n**| charge | CREATE TABLE `charge` (**\n`id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n`user_id` int(11) NOT NULL COMMENT '用户ID',\n`price` decimal(60,2) NOT NULL COMMENT '费用',\n`type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0为保证金 1为余额',\n`create_time` int(11) NOT NULL,\n`update_time` int(11) NOT NULL,\nPRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8 |\n```\n**骑行记录表：**\n```\n**| record | CREATE TABLE `record` (**\n`id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n`bike_id` int(11) NOT NULL COMMENT '单车ID',\n`user_id` int(11) NOT NULL COMMENT '用户ID',\n`end_time` int(11) NOT NULL COMMENT '结束时间',\n`start_time` int(11) NOT NULL COMMENT '开始时间',\n`total_price` decimal(10,0) NOT NULL COMMENT '总价格',\n`start_long` varchar(50) NOT NULL COMMENT '开始经度',\n`start_lati` varchar(50) NOT NULL COMMENT '开始纬度',\n`end_long` varchar(50) NOT NULL COMMENT '结束经度',\n`end_lati` varchar(50) NOT NULL COMMENT '结束纬度',\n`create_time` int(11) NOT NULL,\n`update_time` int(11) NOT NULL,\nPRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8 |\n```\n# 核心知识体系\n## 1.thinkphp5.0相关的知识\n* TP5三大核心：路由、控制器、模型\n* 以ORM的方式查询数据库\n* 使用TP5验证器Validate构建整个验证层\n* 开发环境和生产环境下不同的全局异常处理机制\n* TP5缓存的使用\n* 在TP5中使用数据库事务\n## 2.微信小程序＋微信支付\n* 微信小程序登录状态维护\n* 微信支付接入\n* Class和Module面向对象的思维构建前端代码\n* 体验优化\n## 3.API接口的设计\n* 采用RESTFul API风格\n* （RESTFul API风格可参考GitHub 开发者文档）\n* 返回码、URL语义、HTTP动词、错误码、异常返回\n* 使用Token令牌来构建用户授权体系\n* API版本控制（v1、v2）\n\n#ofo页面逻辑和所需接口分析\n## 1.首页页面逻辑与接口分析\n![](http://upload-images.jianshu.io/upload_images/7689038-119f7972ccf7ff65.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n根据效果图，很明显我们知道肯定需要一个获取单车信息的接口，接口代码如下：\n```php\n/**\n     * @return false|\\PDOStatement|string|\\think\\Collection\n     * @throws BikeException\n     * 获取单车的位置信息\n     */\n    public function getBicyclePosition() {\n        $bikes = BikeModel::getBicyclePosition();\n        if(!$bikes) {\n           throw new BikeException();\n        }\n        return $bikes;\n    }\n```\n立即用车按钮分析，首先我们需要先判断有没有登录，登录我们使用的是token令牌（**后面会在个人中心登录按钮讲下如何生成token令牌，如何利用tp5的缓存，使token令牌有有效期**），如果令牌存在，我们还得判断令牌是否有效，否则重新登录，如果验证通过，我们还得判断这个用户是否已经有押金，如果没有押金，跳到充值页面去充值,否则跳转到用车页面，根据分析，我们需要一个验证token是否有效的接口，接口代码如下，\n```php\n/**\n     * @return bool\n     * @throws TokenException\n     * 验证token\n     */\n    public function verifyToken() {\n        $token = Request::instance()->header('token');\n        $var = Cache::get($token);\n        if(!$var) {\n            throw new TokenException([\n                'msg'=>'token已经过期',\n                'errorCode'=>10002\n            ]);\n        }\n        return true;\n    }\n```\n我们还需要一个获取用户信息的接口，判断是否有押金，接口代码如下：\n```php\n/**\n     * @return null|static\n     * @throws UserException\n     * 获取用户的信息\n     */\n    public function getUserInfo(){\n        $uid = Token::getCurrentUid();\n        $user = UserModel::get($uid);\n        if(!$user) {\n            throw new UserException();\n        }\n        return $user;\n    }\n```\n故障按钮分析：同样的我们需要验证是否登录，登录是否过期，否则我们跳转到登录页面。（**注意：我们需要把用户的初始位置，记录到小程序的缓存中，因为骑行记录表需要记录用户的初始位置**）\n## 2.登录页面逻辑和所需接口分析\n关于使用token令牌的好处，请自行百度，首先我先用一张图来说明微信小程序如何获取token：\n![](http://upload-images.jianshu.io/upload_images/7689038-bafd18220fb2ef8a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n根据效果图，我们需要获取token令牌接口，接口代码如下：\n```php\n /**\n     * @param $code\n     * @return array\n     * 获取token\n     */\n    public function getToken($code) {\n        (new TokenGet())->goCheck();\n        $user = new UserToken($code);\n        $token = $user->get();\n        return [\n            'token'=>$token\n        ];\n    }\n```\n\n设置token的有效期，把token存储在服务器端的缓存中，返回token，客户端获取到token，存储到缓存中，双向存储token，以后每次访问接口都携带token,更加安全，有效的防止有人伪造token获取接口的信息\n## 3.个人中心页面逻辑和所需接口分析\n\n![](http://upload-images.jianshu.io/upload_images/7689038-546a221901e0f733.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n根据效果图，点击我的钱包按钮需要跳转到我的钱包页面，我们需要一个获取用户信息的接口，接口代码如下：\n```php\n/**\n     * @return null|static\n     * @throws UserException\n     * 获取用户的信息\n     */\n    public function getUserInfo(){\n        $uid = Token::getCurrentUid();\n        $user = UserModel::get($uid);\n        if(!$user) {\n            throw new UserException();\n        }\n        return $user;\n    }\n```\n退出登录按钮：我们需要删除本地token，跳转到登录页面\n\n## 4.充值页面逻辑和接口分析\n\n根据效果图：我们需要一个充值的接口，因为是个人开发，没有商户号，所以微信支付就没有做，不过其实微信支付也并不难，附上微信支付的流程：\n```php\n商户系统和微信支付系统主要交互说明：\n步骤1：用户在商户APP中选择商品，提交订单，选择微信支付。\n步骤2：商户后台收到用户支付单，调用微信支付统一下单接口。参见【[统一下单API](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1)】。\n步骤3：统一下单接口返回正常的prepay_id，再按签名规范重新生成签名后，将数据传输给APP。参与签名的字段名为appid，partnerid，prepayid，noncestr，timestamp，package。注意：package的值格式为Sign=WXPay\n步骤4：商户APP调起微信支付。api参见本章节【[app端开发步骤说明](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5)】\n步骤5：商户后台接收支付通知。api参见【[支付结果通知API](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_7)】\n步骤6：商户后台查询支付结果。，api参见【[查询订单API](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_2)】\n```\n这个接口需要注意的是，从哪个页面过来的，从首页过来的，应该就是押金充值，从我的钱包页面和支付页面过来的，就应该是余额充值，根据form不同，我们数据库充值记录表里面的type就不同，type为1代表余额充值，type为1为押金充值，接口代码如下：\n\n```php\n/**\n     * @param $guarantee\n     * 充值\n     */\n    public function pay($from,$price) {\n        $type = 1;\n        if($from == 'index') {\n            $type = 0;\n        }else if($from == 'wallet' || $from == 'pay') {\n            $type = 1;\n        }\n        $uid = Token::getCurrentUid();\n        Db::startTrans();\n        try{\n            if($type == 1) {\n                $user = UserModel::get($uid);\n\n                $price = $price + $user->balance;\n                $result = new UserModel();\n                $res = $result->save(['balance'=>$price],['id'=>$uid]);\n            }else {\n                $res = UserModel::update(['guarantee'=>$price],['id'=>$uid]);\n            }\n            $rel = Charge::create([\n                'price'=>$price,\n                'type'=>$type,\n                'user_id'=>$uid\n            ]);\n            if($rel && $res) {\n                Db::commit();\n            }\n        }catch (Exception $e) {\n            Db::rollback();\n            throw new UserException([\n                'msg'=>'充值失败'\n            ]);\n        }\n    }\n```\n\n## 5.立即用车页面逻辑与接口分析\n\n![](http://upload-images.jianshu.io/upload_images/7689038-29053d2f52db2f09.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n根据效果图，我们需要一个获取单车密码的接口，根据用户输入的ID，获取单车的信息，如果is_show为1，服务器抛出自定义的异常，单车正在被使用，type为1，单车被报修，出现故障，不能使用，单车如果不存在，抛出异常，单车不存在。获取到单车的密码后，携带密码和单车号到结果页面，接口代码如下：\n```php\n/**\n     * @param $id\n     * @return array|false|\\PDOStatement|string|\\think\\Model\n     * @throws BikeException\n     * 根据单车的ID获取单车的信息\n     */\n    public function getBikeByID($id) {\n//        (new IsMustBePostiveInt())->goCheck();\n        $bike = BikeModel::getBikeByID($id);\n        if(!$bike) {\n            throw new BikeException([\n                'msg'=>'该车牌号不存在'\n            ]);\n        }\n        if($bike['is_show'] == 1){\n            throw new BikeException([\n                'msg'=>'此单车正在被使用',\n                'errorCode'=>10001\n            ]);\n        }\n        if($bike['type'] == 1) {\n            throw new BikeException([\n                'msg'=>'此单车多次被报修，暂不可使用',\n                'errorCode'=>10002\n            ]);\n        }\n        return $bike;\n    }\n}\n```\n## 6.计时页面逻辑和接口分析\n\n![](http://upload-images.jianshu.io/upload_images/7689038-6da49b0ba7c32fe7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n根据效果图：计时开始时，我们需要把单车的使用状态改变，改变为正在使用状态，接口代码如下：\n```php\n/**\n     * @param $id\n     * 修改单车的使用状态\n     */\n    public function updateBikeStatus($type = 0,$id) {\n//        (new IsMustBePostiveInt())->goCheck();\n        if($type == 0) {\n            //锁定单车，单车在被使用中\n            $data = [\n                'is_show'=>1\n            ];\n        }elseif ($type == 1) {\n            //释放单车，单车恢复使用\n            $data = [\n                'is_show'=>0\n            ];\n        }elseif ($type == 2) {\n            //单车出现故障\n            $data = [\n                'type'=>1\n            ];\n        }elseif ($type == 3) {\n            //单车恢复正常\n            $data = [\n                'type'=>0\n            ];\n        }\n\n        $res = \\app\\api\\model\\Bike::update($data,['id'=>$id]);\n        if($res) {\n            return true;\n        }else {\n            echo false;\n        }\n    }\n```\n## 7.故障页面逻辑和接口分析\n根据效果图，我们首先需要一个获取故障分类名称的接口，接口代码如下：\n```php\n /**\n     * @return false|\\PDOStatement|string|\\think\\Collection\n     * 获取问题的分类信息\n     */\n    public function getTroubleCate() {\n        $res = new \\app\\api\\model\\TroubleCate();\n        $troubleCate = $res->select();\n        return $troubleCate;\n    }\n```\n然后提交的时候，我们需要一个记录故障的接口，这个接口中，我们首先需要判断，如果没有选择车牌损坏，则必须填写车牌号，否则服务器返回自定义的异常，请输入单车号，单车和故障很明显是多对多的关系，我们在记录的时候，还要写到另外一张表中去，有记录ID和分类ID组成的主键的表，同时我们根据单车的ID还得修改单车的状态，接口代码如下：\n```php\npublic function recordTrouble($record) {\n        //分为两种情况，车牌损坏，车牌未损坏\n       //如果有车牌号码，先判断单车是否存在，不存在，抛出异常，\n        //如果存在，写到trouble_record表，根据trouble_record\n        //的id，还有trouble_id写到bike_trouble表，多对多表，全部写入成功之后，\n        //修改bike表的type值，用到事务，要么失败，要么成功\n        $bikeID = $record['inputValue']['num'];\n        //2代表车牌被损坏，看不到车牌号码\n        if(!in_array(2,$record['checkboxValue'])) {\n            if($bikeID) {\n                $bike = new Bike();\n                $bike->getBikeByID($bikeID);\n            }else {\n                throw new BikeException([\n                    'msg'=>'请输入单车编号',\n                    'errorCode'=>10003\n                ]);\n            }\n        }\n        try {\n            Db::startTrans();\n            $address = $record['address'];\n            $uid = \\app\\api\\service\\Token::getCurrentUid();\n            $troubleRecord = new \\app\\api\\model\\TroubleRecord();\n            $troubleRecord->user_id=$uid;\n            $troubleRecord->bike_id=$bikeID;\n            $troubleRecord->longitude=$address['start_long'];\n            $troubleRecord->latitude=$address['start_lati'];\n            $troubleRecord->img=json_encode($record['picUrls']);\n            $troubleRecord->remark=$record['inputValue']['desc'];\n            //更新故障记录表troubleRecord\n            $troubleRecord->save();\n\n            $resID = $troubleRecord->id;\n\n\n            $troublesID = $record['checkboxValue'];\n            $newArr = array();\n            foreach ($troublesID as $k=>$v) {\n                $newArr[$k]['trouble_id'] = $v;\n                $newArr[$k]['record_id'] = $resID;\n            }\n            $bikeTrouble = new BikeTrouble();\n            //更新故障表bikeTrouble表\n            $rel = $bikeTrouble->saveAll($newArr);\n\n            if($bikeID) {\n                //修改单车的状态，发送了故障\n                $bike = new Bike();\n                $bike->updateBikeStatus(2,$bikeID);\n            }\n            if($resID && $rel) {\n                Db::commit();\n            }\n        }catch (Exception $e) {\n            Db::rollback();\n        }\n    }\n```\n## 8.支付页面的逻辑和接口分析\n\n![](http://upload-images.jianshu.io/upload_images/7689038-33714ae08978d9e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n根据效果图：我们需要一个记录骑行的接口，这个接口中，这里有对多张表的操作，所以我们利用了tp的事务（**注意：mysql数据引擎MyISAM不支持事务**），提高数据库数据的一致性，我们需要记录用户的开始地址，开始时间，结束地址，结束时间，总价格，用户的id，单车的id等等，我们还需要修改用户表的余额，同时修改小程序缓存的余额，**关键点的是，我们还要再次获取用户的地址，及时修改单车的使用状态和位置，便于其他用户的使用，小黄车没有GPS定位系统，而是巧妙的利用了用户的地址**，这里我们看下小黄车的整个使用流程：\n![](http://upload-images.jianshu.io/upload_images/7689038-c4a7dc28519c0c4b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300)\n\n接口代码如下：\n```\n /**\n     * @param $start_time\n     * @param $bikeID\n     * @param $end_time\n     * @param $start_long\n     * @param $start_lati\n     * @param $end_long\n     * @param $end_lati\n     * @param $price\n     * 用户骑行后记录到数据库\n     */\n    public function record($start_time,$bikeID,$end_time,$start_long,$start_lati,$end_long,$end_lati,$price) {\n        $uid = Token::getCurrentUid();\n        $data = [\n            'start_time'=>$start_time,\n            'end_time'=>$end_time,\n            'start_long'=>$start_long,\n            'start_lati'=>$start_lati,\n            'end_lati'=>$end_lati,\n            'end_long'=>$end_long,\n            'total_price'=>$price,\n            'user_id'=>$uid,\n            'bike_id'=>$bikeID\n        ];\n        Db::startTrans();\n        try {\n            //创建记录\n            $res = Record::create($data);\n\n            //修改用户的余额\n            $user = new UserModel();\n            $userInfo = $user->find($uid);\n            $data = [\n                'balance'=>$userInfo->balance-$price\n            ];\n            $rel = $user->save($data,['id'=>$uid]);\n\n\n            //修改小黄车的状态和位置\n            $bikeData = [\n                'is_show'=>'0',\n                'latitude'=>$end_lati,\n                'longitude'=>$end_long\n            ];\n            $rs = \\app\\api\\model\\Bike::update($bikeData,['id'=>$bikeID]);\n\n\n\n            if($res && $rel && $rs) {\n               echo 'success';\n                Db::commit();\n            }\n        }catch (Exception $e) {\n            Db::rollback();\n        }\n    }\n```\n\n# 结语\n> - 到这里，ofo小程序的制作就到了尾声了。开篇我们简单进行了数据库的设计，然后一个一个页面从页面分析，到完成接口设计，分别响应着不同的业务逻辑，有的页面与页面之间有数据往来，我们就通过跳转页面传参或设置本地存储来将它们建立起联系，环环相扣，构建起了整个小程序的基本功能，使原本的ofo小程序有了灵魂。\n\n> - 这个项目做完，使我对前后端分离理解深刻，注意代码的复用性，实践才是王道，这个项目采用了tp5框架，自定义了全局异常类，自定义验证器，加深了我对AOP思想的理解，使用restful API设计接口，更加符合规范。\n\n> - 源码在我的github主页上面，需要的请移步下载[github链接](https://github.com/yefangyong/ofo)，如果喜欢，请给一个start，谢谢\n"
  },
  {
    "path": "application/.htaccess",
    "content": "deny from all"
  },
  {
    "path": "application/admin/config.php",
    "content": "<?php\nreturn [\n    'default_return_type'=>'html'\n];"
  },
  {
    "path": "application/admin/controller/Base.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/12/14\n * Time: 10:29\n */\n\nnamespace app\\admin\\controller;\n\n\nuse think\\Controller;\nuse think\\Exception;\n\nclass Base extends Controller\n{\n    public $model;\n\n    /**\n     * @return string\n     * 公用的修改状态和删除的方法\n     */\n    public function status() {\n        $params = request()->param();\n        if(!intval($params['id'])){\n            return show(0,'id不合法');\n        }\n        //获取当前控制器的名字，一般控制器名字和model和数据表名字一直，如果不一致，我们可以在model里面，直接声明model\n        //例如 $this->model = 'model名'\n        $model = $this->model?$this->model:request()->controller();\n\n        try {\n            $res = model($model)->save(['status'=>$params['status']],['id'=>$params['id']]);\n        }catch (Exception $e) {\n            return show(0,$e->getMessage());\n        }\n        $trouble = model($model)->get($params['id']);\n        if(isset($trouble->bike_id ) && $trouble->bike_id != 0 ) {\n            try {\n                $rel = model('Bike')->save(['type'=>0],['id'=>$trouble->bike_id ]);\n            }catch (Exception $e) {\n                return show(0,$e->getMessage());\n            }\n        }\n        if($res) {\n            return show(1,'操作成功');\n        }else {\n            return show(0,'操作失败');\n        }\n    }\n}"
  },
  {
    "path": "application/admin/controller/Bike.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/12\n * Time: 17:31\n */\n\nnamespace app\\admin\\controller;\n\n\nuse think\\Controller;\n\nclass Bike extends Controller\n{\n    public function index() {\n        $bikes = \\app\\admin\\model\\Bike::getAllBike();\n        return $this->fetch('',['bike'=>$bikes]);\n    }\n\n    public function add() {\n        if($_POST) {\n            $passwd = $_POST['password'];\n            $address = $_POST['address'];\n            if(empty($passwd) || empty($address)) {\n                return show(0,'请填写密码或者地址');\n            }\n            $result = \\TxMap::getLngLat($address);\n            $lat = $result['result']['location']['lat'];\n            $lng = $result['result']['location']['lng'];\n            $data = [\n                'latitude'=>$lat,\n                'longitude'=>$lng,\n                'is_show'=>0,\n                'type'=>0,\n                'password'=>$passwd\n            ];\n            $res = \\app\\admin\\model\\Bike::create($data);\n            if($res) {\n                return show(1,'添加成功');\n            }else {\n                return show(0,'添加失败');\n            }\n        }else {\n\n            return $this->fetch();\n        }\n\n    }\n}"
  },
  {
    "path": "application/admin/controller/Charge.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/13\n * Time: 10:08\n */\n\nnamespace app\\admin\\controller;\n\n\nuse think\\Controller;\n\nclass Charge extends Controller\n{\n    public function index() {\n        $charge =  \\app\\admin\\model\\Charge::getAllCharge();\n        return $this->fetch('',['charge'=>$charge]);\n    }\n}"
  },
  {
    "path": "application/admin/controller/Index.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/12\n * Time: 14:19\n */\n\nnamespace app\\admin\\controller;\n\nuse My\\RedisPackage;\nuse think\\cache\\driver\\Memcached;\nuse think\\Controller;\n\nclass Index extends Controller\n{\n    public function index() {\n//        $memcache = new Memcached();\n//       session('test','测试');\n        return $this->fetch();\n\n\n    }\n\n    public function welcome() {\n        return \"欢迎访问享骑单车小程序后台管理系统\";\n    }\n}"
  },
  {
    "path": "application/admin/controller/Record.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/13\n * Time: 10:58\n */\n\nnamespace app\\admin\\controller;\n\nuse think\\Controller;\n\nclass Record extends Controller\n{\n    /**\n     * @return mixed\n     * 获取骑行记录\n     */\n    public function index() {\n        $records = \\app\\admin\\model\\Record::getAllRecord();\n        return $this->fetch('',['records'=>$records]);\n    }\n}"
  },
  {
    "path": "application/admin/controller/Trouble.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/13\n * Time: 11:58\n */\n\nnamespace app\\admin\\controller;\n\n\n\nuse app\\admin\\model\\TroubleCate;\nuse app\\admin\\model\\TroubleRecord;\nuse think\\Controller;\n\nclass Trouble extends Base\n{\n    public $model = 'trouble_record';\n    /**\n     * @return mixed\n     * 故障列表\n     */\n    public function index() {\n        $troubles = TroubleRecord::getAllTrouble();\n        $reason = '';\n       foreach ($troubles as $key=>$val) {\n          foreach ($val['trouble_cate'] as $value) {\n              $reason .= ','.$value['name'];\n          }\n          $reason = substr($reason,1);\n          $troubles[$key]['reason'] = $reason;\n       }\n       return $this->fetch('',['trouble'=>$troubles]);\n    }\n\n    /**\n     * @return mixed\n     * 故障分类列表\n     */\n    public function troubleCate() {\n        $result = TroubleCate::getTroubleCate();\n        return $this->fetch('',['troubleCate'=>$result]);\n    }\n\n    /**\n     * @return mixed|void\n     * 分类添加\n     */\n    public function add(){\n        if($_POST) {\n            if(empty($_POST['catename'])) {\n                return show(0,'请输入分类名称');\n            }else {\n                $data = [\n                    'name'=>$_POST['catename'],\n                ];\n                $res = TroubleCate::create($data);\n                if($res) {\n                    return show(1,'添加成功');\n                }else {\n                    return show(0,'添加失败');\n                }\n            }\n        }else{\n            return $this->fetch();\n        }\n    }\n}"
  },
  {
    "path": "application/admin/controller/User.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/12\n * Time: 15:26\n */\n\nnamespace app\\admin\\controller;\n\n\nuse think\\Controller;\n\nclass User extends Controller\n{\n    public function index() {\n        $user = \\app\\admin\\model\\User::getAllUser();\n        return $this->fetch('',['user'=>$user]);\n    }\n}"
  },
  {
    "path": "application/admin/model/Bike.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/12\n * Time: 17:31\n */\n\nnamespace app\\admin\\model;\n\n\nuse think\\Model;\n\nclass Bike extends Model\n{\n    public static function getAllBike() {\n        return self::order('create_time','desc')->paginate(config('pagination.list_rows'))->each(function ($item, $key){\n            $lnt = $item->latitude;\n            $lgt = $item->longitude;\n            $result = \\TxMap::getAddress($lgt,$lnt);\n            $item->address = $result['result']['formatted_addresses']['recommend'];\n            return $item;\n        });\n    }\n}"
  },
  {
    "path": "application/admin/model/BikeTrouble.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/13\n * Time: 13:30\n */\n\nnamespace app\\admin\\model;\n\n\nuse think\\Model;\n\nclass BikeTrouble extends Model\n{\n\n}"
  },
  {
    "path": "application/admin/model/Charge.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/13\n * Time: 10:18\n */\n\nnamespace app\\admin\\model;\n\n\nuse think\\Model;\n\nclass Charge extends Model\n{\n    /**\n     * @param $value\n     * @param $data\n     * @return string\n     * 改变获取到数据的属性值\n     */\n    public function getTypeAttr($value,$data) {\n        if($value == 0) {\n            return $value ='押金充值';\n        }else {\n            return $value = '余额充值';\n        }\n    }\n    /**\n     * @return \\think\\model\\relation\\BelongsTo\n     * 关联用户表 多对一关联\n     */\n    public function user(){\n        return $this->belongsTo('User','user_id');\n    }\n\n    /**\n     * @return \\think\\Paginator\n     * 获取所有的充值记录\n     */\n    public static function getAllCharge() {\n        $pagination = config('pagination.charge');\n        return self::order('create_time','desc')->with('user')->paginate($pagination['list_row']);\n    }\n}"
  },
  {
    "path": "application/admin/model/Record.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/13\n * Time: 10:58\n */\n\nnamespace app\\admin\\model;\n\n\n\n\nuse think\\Model;\n\nclass Record extends Model\n{\n    /**\n     * @return \\think\\model\\relation\\BelongsTo\n     * 关联单车表\n     */\n    public function bike() {\n        return $this->belongsTo('bike','bike_id');\n    }\n\n    /**\n     * @return \\think\\model\\relation\\BelongsTo\n     * 关联用户表\n     */\n    public function user() {\n        return $this->belongsTo('user','user_id');\n    }\n\n\n    /**\n     * @return $this\n     * 获取所有的记录\n     */\n    public static function getAllRecord() {\n        return self::order('create_time','desc')->with(['bike','user'])->paginate(config('pagination.list_rows'))->each(function($item,$key){\n            $slnt = $item->start_lati;\n            $slgt = $item->start_long;\n            $sresult =  \\TxMap::getAddress($slgt,$slnt);\n            if($sresult['status'] !=0) {\n                $item->start_address = '' ;\n            }else {\n                $item->start_address = $sresult['result']['formatted_addresses']['recommend'];\n            }\n            $elnt = $item->end_lati;\n            $elgt = $item->end_long;\n            $eresult = \\TxMap::getAddress($elgt,$elnt);\n            if($eresult['status'] !=0) {\n                $item->end_address = '' ;\n            }else {\n                $item->end_address = $eresult['result']['formatted_addresses']['recommend'];\n            }\n            return $item;\n            });\n    }\n}"
  },
  {
    "path": "application/admin/model/TroubleCate.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/13\n * Time: 11:59\n */\n\nnamespace app\\admin\\model;\n\n\nuse think\\Model;\n\nclass TroubleCate extends Model\n{\n    /**\n     * @return \\think\\Paginator\n     * 获取故障分类\n     */\n    public static function getTroubleCate() {\n        return self::order('create_time','desc')->paginate(config('pagination.list_rows'));\n    }\n}"
  },
  {
    "path": "application/admin/model/TroubleRecord.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/13\n * Time: 13:31\n */\n\nnamespace app\\admin\\model;\n\n\nuse think\\Model;\n\nclass TroubleRecord extends Model\n{\n    /**\n     * @return \\think\\model\\relation\\BelongsToMany\n     * 关联troubleCate表，多对多关联\n     */\n    public function troubleCate() {\n        return $this->belongsToMany('troubleCate','bike_trouble','trouble_id','record_id');\n    }\n\n\n    /**\n     * @return \\think\\model\\relation\\BelongsTo\n     * 关联用户表\n     */\n    public function user() {\n        return $this->belongsTo('user','user_id');\n    }\n\n    /**\n     * @return $this\n     * 获取所有的故障列表\n     */\n    public static function getAllTrouble(){\n        return self::order('create_time','desc')->with(['troubleCate','user','troubleCate'])->paginate(config('pagination.list_rows'))->each(function($item,$key){\n            $lnt = $item->latitude;\n            $lgt = $item->longitude;\n            $result = \\TxMap::getAddress($lgt,$lnt);\n            if($result['status'] != 0) {\n                $item->address = '' ;\n            }else {\n                $item->address = $result['result']['formatted_addresses']['recommend'];\n            }\n            return $item;\n        });\n    }\n}"
  },
  {
    "path": "application/admin/model/User.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/12\n * Time: 16:02\n */\n\nnamespace app\\admin\\model;\n\n\nuse think\\Model;\n\nclass User extends Model\n{\n    public static function getAllUser() {\n        $pagination = config('pagination.user');\n        return self::order('create_time','desc')->paginate($pagination['list_row']);\n    }\n}"
  },
  {
    "path": "application/admin/view/bike/add.html",
    "content": "{include file=\"public/header\" /}\n<body>\n<article class=\"page-container\">\n    <form class=\"form form-horizontal\" id=\"yfycms-form\">\n        <div class=\"row cl\">\n            <label class=\"form-label col-xs-4 col-sm-3\"><span class=\"c-red\">*</span>车辆密码：</label>\n            <div class=\"formControls col-xs-8 col-sm-9\">\n                <input type=\"password\" class=\"input-text\" value=\"\" placeholder=\"请输入车辆的密码\" id=\"password\" name=\"password\">\n            </div>\n        </div>\n        <div class=\"row cl\">\n            <label class=\"form-label col-xs-4 col-sm-3\"><span class=\"c-red\">*</span>所在位置：</label>\n            <div class=\"formControls col-xs-8 col-sm-9\">\n                <input type=\"text\" class=\"input-text\" value=\"\" placeholder=\"请输入车辆的位置\" id=\"username\" name=\"address\">\n            </div>\n        </div>\n        <div class=\"row cl\">\n            <div class=\"col-xs-8 col-sm-9 col-xs-offset-4 col-sm-offset-3\">\n                <input class=\"btn btn-primary radius\" type=\"button\" id=\"yfycms-button-submit\" value=\"&nbsp;&nbsp;提交&nbsp;&nbsp;\">\n            </div>\n        </div>\n    </form>\n</article>\n<script>\n    var SCOPE = {\n        'save_url':\"{:url('bike/add')}\",\n        'jump_url':\"{:url('bike/index')}\"\n    };\n</script>\n{include file=\"public/footer\" /}\n</body>\n</html>\n"
  },
  {
    "path": "application/admin/view/bike/index.html",
    "content": "<!--包含头部文件-->\n{include file=\"public/header\" /}\n<body>\n<nav class=\"breadcrumb\"><i class=\"Hui-iconfont\">&#xe67f;</i> 首页 <span class=\"c-gray en\">&gt;</span> 用户管理 <span class=\"c-gray en\">&gt;</span> 用户列表 <a class=\"btn btn-success radius r\" style=\"line-height:1.6em;margin-top:3px\" href=\"javascript:location.replace(location.href);\" title=\"刷新\" ><i class=\"Hui-iconfont\">&#xe68f;</i></a></nav>\n<div class=\"page-container\">\n    <div class=\"mt-20\">\n        <div class=\"cl pd-5 bg-1 bk-gray mt-20\"> <span class=\"l\"> <a class=\"btn btn-primary radius\" onclick=\"edit_add('添加车辆','{:url('Bike/add')}')\" href=\"javascript:;\"><i class=\"Hui-iconfont\">&#xe600;</i> 添加车辆</a></span> <span class=\"r\"></span> </div>\n        <table class=\"table table-border table-bordered table-bg table-hover table-sort o2o_yfycms\">\n            <thead>\n            <tr class=\"text-c\">\n                <th width=\"40\"><input name=\"\" type=\"checkbox\" value=\"\"></th>\n                <th width=\"80\">ID</th>\n                <th width=\"150\">车辆位置</th>\n                <th width=\"30\">车辆密码</th>\n                <th width=\"30\">使用状态</th>\n                <th width=\"30\">故障状态</th>\n                <th width=\"60\">创建时间</th>\n                <th width=\"100\">操作</th>\n            </tr>\n            </thead>\n            <tbody>\n            {volist name=\"bike\" id=\"vo\"}\n            <tr class=\"text-c\">\n                <td><input name=\"\" type=\"checkbox\" value=\"{$vo.id}\"></td>\n                <td>{$key+1}</td>\n                <td>{$vo.address}</td>\n                <td>{$vo.password}</td>\n                <td class=\"td-status\"><span class=\"label radius {$vo.is_show ? 'label-danger':'label-success'}\">{$vo.is_show|userStatus}</span></td>\n                <td class=\"td-status\"><span class=\"label radius {$vo.type ? 'label-danger':'label-success'}\">{$vo.type|troubleStatus}</span></td>\n                <td>{$vo.create_time}</td>\n                <td class=\"td-manage\"><a style=\"text-decoration:none\" class=\"ml-5 o2o_status\"  attr-id=\"{$vo.id}\" attr-status=\"-1\" href=\"javascript:;\" title=\"删除\"><i class=\"Hui-iconfont\">&#xe6e2;</i></a></td>\n            </tr>\n            {/volist}\n            </tbody>\n        </table>\n\n    </div>\n</div>\n<div class=\"cl pd-5 bg-1 bk-gray mt-20 tp5\">{$bike->render()}</div>\n<!--包含头部文件-->\n{include file=\"public/footer\" /}\n<script>\n    var SCOPE ={\n        'listorder_url':\"{:url('category/listorder')}\",\n        'jump_url':\"{:url('category/index')}\",\n        'status_url':\"{:url('category/status')}\",\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "application/admin/view/charge/index.html",
    "content": "<!--包含头部文件-->\n{include file=\"public/header\" /}\n<body>\n<nav class=\"breadcrumb\"><i class=\"Hui-iconfont\">&#xe67f;</i> 首页 <span class=\"c-gray en\">&gt;</span> 充值管理 <span class=\"c-gray en\">&gt;</span> 充值列表 <a class=\"btn btn-success radius r\" style=\"line-height:1.6em;margin-top:3px\" href=\"javascript:location.replace(location.href);\" title=\"刷新\" ><i class=\"Hui-iconfont\">&#xe68f;</i></a></nav>\n<div class=\"page-container\">\n    <div class=\"mt-20\">\n        <table class=\"table table-border table-bordered table-bg table-hover table-sort o2o_yfycms\">\n            <thead>\n            <tr class=\"text-c\">\n                <th width=\"40\"><input name=\"\" type=\"checkbox\" value=\"\"></th>\n                <th width=\"80\">ID</th>\n                <th width=\"100\">用户昵称</th>\n                <th width=\"30\">充值金额</th>\n                <th width=\"150\">充值类型</th>\n                <th width=\"60\">创建时间</th>\n                <th width=\"100\">操作</th>\n            </tr>\n            </thead>\n            <tbody>\n            {volist name=\"charge\" id=\"vo\"}\n            <tr class=\"text-c\">\n                <td><input name=\"\" type=\"checkbox\" value=\"{$vo.id}\"></td>\n                <td>{$key+1}</td>\n                <td>{$vo.user.nickname}</td>\n                <td class=\"td-status\"><span class=\"label label-success radius\">{$vo.price}</span></td>\n                <td>{$vo.type}</td>\n                <td class=\"td-status\"><span class=\"label label-success radius\">{$vo.create_time}</span></td>\n                <td class=\"td-manage\"><a style=\"text-decoration:none\" class=\"ml-5 o2o_status\"  attr-id=\"{$vo.id}\" attr-status=\"-1\" href=\"javascript:;\" title=\"删除\"><i class=\"Hui-iconfont\">&#xe6e2;</i></a></td>\n            </tr>\n            {/volist}\n            </tbody>\n        </table>\n\n    </div>\n</div>\n<div class=\"cl pd-5 bg-1 bk-gray mt-20 tp5\">{$charge->render()}</div>\n<!--包含头部文件-->\n{include file=\"public/footer\" /}\n<script>\n    var SCOPE ={\n        'listorder_url':\"{:url('category/listorder')}\",\n        'jump_url':\"{:url('category/index')}\",\n        'status_url':\"{:url('category/status')}\",\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "application/admin/view/index/index.html",
    "content": "<!--包含头部文件-->\n{include file=\"public/header\" /}\n<body>\n<header class=\"navbar-wrapper\">\n    <div class=\"navbar navbar-fixed-top\">\n        <div class=\"container-fluid cl\"> <a class=\"logo navbar-logo f-l mr-10 hidden-xs\" href=\"\">享骑单车后台管理系统</a> <a class=\"logo navbar-logo-m f-l mr-10 visible-xs\" href=\"\"></a> <span class=\"logo navbar-slogan f-l mr-10 hidden-xs\"></span> <a aria-hidden=\"false\" class=\"nav-toggle Hui-iconfont visible-xs\" href=\"javascript:;\">&#xe667;</a>\n\n            <nav id=\"Hui-userbar\" class=\"nav navbar-nav navbar-userbar hidden-xs\">\n                <ul class=\"cl\">\n                    <li>超级管理员</li>\n                    <li class=\"dropDown dropDown_hover\"> <a href=\"#\" class=\"dropDown_A\">admin <i class=\"Hui-iconfont\">&#xe6d5;</i></a>\n                        <ul class=\"dropDown-menu menu radius box-shadow\">\n                            <li><a href=\"#\">个人信息</a></li>\n                            <li><a href=\"#\">切换账户</a></li>\n                            <li><a href=\"#\">退出</a></li>\n                        </ul>\n                    </li>\n                    <li id=\"Hui-msg\"> <a href=\"#\" title=\"消息\"><span class=\"badge badge-danger\">1</span><i class=\"Hui-iconfont\" style=\"font-size:18px\">&#xe68a;</i></a> </li>\n                    <li id=\"Hui-skin\" class=\"dropDown right dropDown_hover\"> <a href=\"javascript:;\" class=\"dropDown_A\" title=\"换肤\"><i class=\"Hui-iconfont\" style=\"font-size:18px\">&#xe62a;</i></a>\n                        <ul class=\"dropDown-menu menu radius box-shadow\">\n                            <li><a href=\"javascript:;\" data-val=\"default\" title=\"默认（黑色）\">默认（黑色）</a></li>\n                            <li><a href=\"javascript:;\" data-val=\"blue\" title=\"蓝色\">蓝色</a></li>\n                            <li><a href=\"javascript:;\" data-val=\"green\" title=\"绿色\">绿色</a></li>\n                            <li><a href=\"javascript:;\" data-val=\"red\" title=\"红色\">红色</a></li>\n                            <li><a href=\"javascript:;\" data-val=\"yellow\" title=\"黄色\">黄色</a></li>\n                            <li><a href=\"javascript:;\" data-val=\"orange\" title=\"绿色\">橙色</a></li>\n                        </ul>\n                    </li>\n                </ul>\n            </nav>\n        </div>\n    </div>\n</header>\n<!--包含菜单文件-->\n{include file=\"public/menu\" /}\n<div class=\"dislpayArrow hidden-xs\"><a class=\"pngfix\" href=\"javascript:void(0);\" onClick=\"displaynavbar(this)\"></a></div>\n<section class=\"Hui-article-box\">\n    <div id=\"Hui-tabNav\" class=\"Hui-tabNav hidden-xs\">\n        <div class=\"Hui-tabNav-wp\">\n            <ul id=\"min_title_list\" class=\"acrossTab cl\">\n                <li class=\"active\"><span title=\"我的桌面\" data-href=\"welcome.html\">我的桌面</span><em></em></li>\n            </ul>\n        </div>\n        <div class=\"Hui-tabNav-more btn-group\"><a id=\"js-tabNav-prev\" class=\"btn radius btn-default size-S\" href=\"javascript:;\"><i class=\"Hui-iconfont\">&#xe6d4;</i></a><a id=\"js-tabNav-next\" class=\"btn radius btn-default size-S\" href=\"javascript:;\"><i class=\"Hui-iconfont\">&#xe6d7;</i></a></div>\n    </div>\n    <div id=\"iframe_box\" class=\"Hui-article\">\n        <div class=\"show_iframe\">\n            <div style=\"display:none\" class=\"loading\"></div>\n            <iframe scrolling=\"yes\" frameborder=\"0\" src=\"{:url('index/welcome')}\"></iframe>\n        </div>\n    </div>\n</section>\n<!--包含菜单文件-->\n{include file=\"public/footer\" /}\n</body>\n</html>"
  },
  {
    "path": "application/admin/view/public/footer.html",
    "content": "<script type=\"text/javascript\" src=\"/static/lib/jquery/1.9.1/jquery.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/lib/layer/2.4/layer.js\"></script>\n<script type=\"text/javascript\" src=\"/static/h-ui/js/H-ui.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/admin/js/common.js\"></script>\n<script type=\"text/javascript\" src=\"/static/admin/js/dialog.js\"></script>\n<script type=\"text/javascript\" src=\"/static/h-ui.admin/js/H-ui.admin.js\"></script>"
  },
  {
    "path": "application/admin/view/public/header.html",
    "content": "<!DOCTYPE HTML>\n    <html>\n    <head>\n        <meta charset=\"utf-8\">\n        <meta name=\"renderer\" content=\"webkit|ie-comp|ie-stand\">\n        <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n        <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no\" />\n        <meta http-equiv=\"Cache-Control\" content=\"no-siteapp\" />\n        <LINK rel=\"Bookmark\" href=\"/favicon.ico\" >\n        <LINK rel=\"Shortcut Icon\" href=\"/favicon.ico\" />\n        <!--[if lt IE 9]>\n\n        <script type=\"text/javascript\" src=\"/static/lib/html5shiv.js\"></script>\n        <script type=\"text/javascript\" src=\"/static/lib/respond.min.js\"></script>\n        <![endif]-->\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/static/h-ui/css/H-ui.min.css\" />\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/static/admin/common.css\" />\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/static/h-ui.admin/css/H-ui.admin.css\" />\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/static/lib/Hui-iconfont/1.0.8/iconfont.css\" />\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/static/h-ui.admin/skin/default/skin.css\" id=\"skin\" />\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/static/h-ui.admin/css/style.css\" />\n        <!--[if IE 6]>\n        <script type=\"text/javascript\" src=\"http://lib.h-ui.net/DD_belatedPNG_0.0.8a-min.js\" ></script>\n        <script>DD_belatedPNG.fix('*');</script>\n        <![endif]-->\n        <title>享骑单车小程序后台管理系统</title>\n        <meta name=\"keywords\" content=\"tp5打造o2o平台系统\">\n        <meta name=\"description\" content=\"o2o平台\">\n    </head>\n"
  },
  {
    "path": "application/admin/view/public/menu.html",
    "content": "<aside class=\"Hui-aside\">\n    <div class=\"menu_dropdown bk_2\">\n        <dl id=\"menu-article\">\n            <dt><i class=\"Hui-iconfont\">&#xe616;</i> 用户管理<i class=\"Hui-iconfont menu_dropdown-arrow\">&#xe6d5;</i></dt>\n            <dd>\n                <ul>\n                    <li><a data-href=\"{:url('user/index')}\" data-title=\"用户列表\" href=\"javascript:void(0)\">用户列表</a></li>\n                </ul>\n            </dd>\n        </dl>\n        <dl id=\"menu-picture\">\n            <dt><i class=\"Hui-iconfont\">&#xe613;</i> 车辆管理<i class=\"Hui-iconfont menu_dropdown-arrow\">&#xe6d5;</i></dt>\n            <dd>\n                <ul>\n                    <li><a data-href=\"{:url('bike/index')}\" data-title=\"车辆列表\" href=\"javascript:void(0)\">车辆列表</a></li>\n                    <li><a data-href=\"{:url('bike/add')}\" data-title=\"车辆添加\" href=\"javascript:void(0)\">车辆添加</a></li>\n                </ul>\n            </dd>\n        </dl>\n        <dl id=\"menu-product\">\n            <dt><i class=\"Hui-iconfont\">&#xe620;</i> 充值管理<i class=\"Hui-iconfont menu_dropdown-arrow\">&#xe6d5;</i></dt>\n            <dd>\n                <ul>\n                    <li><a data-href=\"{:url('charge/index')}\" data-title=\"充值管理\" href=\"javascript:void(0)\">充值列表</a></li>\n                </ul>\n            </dd>\n        </dl>\n        <dl id=\"menu-comments\">\n            <dt><i class=\"Hui-iconfont\">&#xe622;</i> 订单管理<i class=\"Hui-iconfont menu_dropdown-arrow\">&#xe6d5;</i></dt>\n            <dd>\n                <ul>\n                    <li><a data-href=\"{:url('record/index')}\" data-title=\"订单列表\" href=\"javascript:;\">订单列表</a></li>\n                </ul>\n            </dd>\n        </dl>\n        <dl id=\"menu-member\">\n            <dt><i class=\"Hui-iconfont\">&#xe60d;</i> 故障管理<i class=\"Hui-iconfont menu_dropdown-arrow\">&#xe6d5;</i></dt>\n            <dd>\n                <ul>\n                    <li><a data-href=\"{:url('trouble/index')}\" data-title=\"故障列表\" href=\"javascript:;\">故障列表</a></li>\n                    <li><a data-href=\"{:url('trouble/troubleCate')}\" data-title=\"故障分类\" href=\"javascript:;\">故障分类</a></li>\n                </ul>\n            </dd>\n        </dl>\n    </div>\n</aside>\n<div class=\"dislpayArrow hidden-xs\"><a class=\"pngfix\" href=\"javascript:void(0);\" onClick=\"displaynavbar(this)\"></a></div>"
  },
  {
    "path": "application/admin/view/record/index.html",
    "content": "<!--包含头部文件-->\n{include file=\"public/header\" /}\n<body>\n<nav class=\"breadcrumb\"><i class=\"Hui-iconfont\">&#xe67f;</i> 首页 <span class=\"c-gray en\">&gt;</span> 订单管理 <span class=\"c-gray en\">&gt;</span> 订单列表 <a class=\"btn btn-success radius r\" style=\"line-height:1.6em;margin-top:3px\" href=\"javascript:location.replace(location.href);\" title=\"刷新\" ><i class=\"Hui-iconfont\">&#xe68f;</i></a></nav>\n<div class=\"page-container\">\n    <div class=\"mt-20\">\n        <table class=\"table table-border table-bordered table-bg table-hover table-sort o2o_yfycms\">\n            <thead>\n            <tr class=\"text-c\">\n                <th width=\"40\"><input name=\"\" type=\"checkbox\" value=\"\"></th>\n                <th width=\"40\">ID</th>\n                <th width=\"40\">单车ID</th>\n                <th width=\"190\">用户昵称</th>\n                <th width=\"40\">费用</th>\n                <th width=\"150\">开始位置</th>\n                <th width=\"150\">结束位置</th>\n                <th width=\"120\">开始时间</th>\n                <th width=\"120\">结束时间</th>\n                <th width=\"120\">创建时间</th>\n                <th width=\"80\">操作</th>\n            </tr>\n            </thead>\n            <tbody>\n            {volist name=\"records\" id=\"vo\"}\n            <tr class=\"text-c\">\n                <td><input name=\"\" type=\"checkbox\" value=\"{$vo.id}\"></td>\n                <td>{$key+1}</td>\n                <td>{$vo.bike_id}</td>\n                <td>{$vo.user.nickname}</td>\n                <td>{$vo.total_price}</td>\n                <td>{$vo.start_address}</td>\n                <td>{$vo.end_address}</td>\n                <td class=\"td-status\"><span class=\"label label-success radius\">{$vo.start_time|date=\"Y-m-d H:i:s\",###}</span></td>\n                <td class=\"td-status\"><span class=\"label label-success radius\">{$vo.end_time|date=\"Y-m-d H:i:s\",###}</span></td>\n                <td>{$vo.create_time}</td>\n                <td class=\"td-manage\"><a style=\"text-decoration:none\" class=\"ml-5 o2o_status\"  attr-id=\"{$vo.id}\" attr-status=\"-1\" href=\"javascript:;\" title=\"删除\"><i class=\"Hui-iconfont\">&#xe6e2;</i></a></td>\n            </tr>\n            {/volist}\n            </tbody>\n        </table>\n\n    </div>\n</div>\n<div class=\"cl pd-5 bg-1 bk-gray mt-20 tp5\">{$records->render()}</div>\n<!--包含头部文件-->\n{include file=\"public/footer\" /}\n<script>\n    var SCOPE ={\n        'listorder_url':\"{:url('category/listorder')}\",\n        'jump_url':\"{:url('category/index')}\",\n        'status_url':\"{:url('category/status')}\",\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "application/admin/view/trouble/add.html",
    "content": "{include file=\"public/header\" /}\n<body>\n<article class=\"page-container\">\n    <form class=\"form form-horizontal\" id=\"yfycms-form\">\n        <div class=\"row cl\">\n            <label class=\"form-label col-xs-4 col-sm-3\"><span class=\"c-red\">*</span>分类名称：</label>\n            <div class=\"formControls col-xs-8 col-sm-9\">\n                <input type=\"text\" class=\"input-text\" value=\"\" placeholder=\"请输入分类的名称\" id=\"catename\" name=\"catename\">\n            </div>\n        </div>\n        <div class=\"row cl\">\n            <div class=\"col-xs-8 col-sm-9 col-xs-offset-4 col-sm-offset-3\">\n                <input class=\"btn btn-primary radius\" type=\"button\" id=\"yfycms-button-submit\" value=\"&nbsp;&nbsp;提交&nbsp;&nbsp;\">\n            </div>\n        </div>\n    </form>\n</article>\n<script>\n    var SCOPE = {\n        'save_url':\"{:url('trouble/add')}\",\n        'jump_url':\"{:url('trouble/index')}\"\n    };\n</script>\n{include file=\"public/footer\" /}\n</body>\n</html>\n"
  },
  {
    "path": "application/admin/view/trouble/index.html",
    "content": "<!--包含头部文件-->\n{include file=\"public/header\" /}\n<body>\n<nav class=\"breadcrumb\"><i class=\"Hui-iconfont\">&#xe67f;</i> 首页 <span class=\"c-gray en\">&gt;</span> 故障管理 <span class=\"c-gray en\">&gt;</span> 故障列表 <a class=\"btn btn-success radius r\" style=\"line-height:1.6em;margin-top:3px\" href=\"javascript:location.replace(location.href);\" title=\"刷新\" ><i class=\"Hui-iconfont\">&#xe68f;</i></a></nav>\n<div class=\"page-container\">\n    <div class=\"mt-20\">\n        <table class=\"table table-border table-bordered table-bg table-hover table-sort o2o_yfycms\">\n            <thead>\n            <tr class=\"text-c\">\n                <th width=\"40\"><input name=\"\" type=\"checkbox\" value=\"\"></th>\n                <th width=\"20\">ID</th>\n                <th width=\"40\">单车ID</th>\n                <th width=\"100\">单车位置</th>\n                <th width=\"160\">报修人</th>\n                <th width=\"100\">报修原因</th>\n                <th width=\"100\">故障图片</th>\n                <th width=\"60\">备注</th>\n                <th width=\"40\">状态</th>\n                <th width=\"70\">创建时间</th>\n                <th width=\"40\">操作</th>\n            </tr>\n            </thead>\n            <tbody>\n            {volist name=\"$trouble\" id=\"vo\"}\n            <tr class=\"text-c\">\n                <td><input name=\"\" type=\"checkbox\" value=\"{$vo.id}\"></td>\n                <td>{$key+1}</td>\n                <td>{$vo.bike_id}</td>\n                <td>{$vo.address}</td>\n                <td>{$vo.user.nickname}</td>\n                <td>{$vo.reason}</td>\n                <td><img width=\"100\" height=\"100\" class=\"picture-thumb\" src=\"{$vo.img}\"></td>\n                <td>{$vo.remark}</td>\n                <td class=\"td-status\"><a class=\"{$vo.status ? '' : 'app-status'}\"  attr-id=\"{$vo.id}\" attr-status=\"1\" attr-message=\"修改\"><span class=\"label radius {$vo.status? 'label-success':'label-danger'}\">{$vo.status|getStatusAttr}</span></a></td>\n                <td>{$vo.create_time}</td>\n                <td class=\"td-manage\"><a style=\"text-decoration:none\" class=\"ml-5 o2o_status\"  attr-id=\"{$vo.id}\" attr-status=\"-1\" href=\"javascript:;\" title=\"删除\"><i class=\"Hui-iconfont\">&#xe6e2;</i></a></td>\n            </tr>\n            {/volist}\n            </tbody>\n        </table>\n\n    </div>\n</div>\n<div class=\"cl pd-5 bg-1 bk-gray mt-20 tp5\">{$trouble->render()}</div>\n<!--包含头部文件-->\n{include file=\"public/footer\" /}\n<script>\n    var SCOPE ={\n        'jump_url':\"{:url('trouble/index')}\",\n        'status_url':\"{:url('trouble/status')}\",\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "application/admin/view/trouble/troublecate.html",
    "content": "<!--包含头部文件-->\n{include file=\"public/header\" /}\n<body>\n<nav class=\"breadcrumb\"><i class=\"Hui-iconfont\">&#xe67f;</i> 首页 <span class=\"c-gray en\">&gt;</span> 故障管理 <span class=\"c-gray en\">&gt;</span> 故障分类 <a class=\"btn btn-success radius r\" style=\"line-height:1.6em;margin-top:3px\" href=\"javascript:location.replace(location.href);\" title=\"刷新\" ><i class=\"Hui-iconfont\">&#xe68f;</i></a></nav>\n<div class=\"page-container\">\n    <div class=\"mt-20\">\n        <div class=\"cl pd-5 bg-1 bk-gray mt-20\"> <span class=\"l\"> <a class=\"btn btn-primary radius\" onclick=\"yfy_s_edit('添加分类','{:url('trouble/add')}',400,200)\" href=\"javascript:;\"><i class=\"Hui-iconfont\">&#xe600;</i> 添加分类</a></span> <span class=\"r\"></span> </div>\n        <table class=\"table table-border table-bordered table-bg table-hover table-sort o2o_yfycms\">\n            <thead>\n            <tr class=\"text-c\">\n                <th width=\"40\"><input name=\"\" type=\"checkbox\" value=\"\"></th>\n                <th width=\"80\">ID</th>\n                <th width=\"100\">故障名称</th>\n                <th width=\"60\">创建时间</th>\n                <th width=\"100\">操作</th>\n            </tr>\n            </thead>\n            <tbody>\n            {volist name=\"troubleCate\" id=\"vo\"}\n            <tr class=\"text-c\">\n                <td><input name=\"\" type=\"checkbox\" value=\"{$vo.id}\"></td>\n                <td>{$vo.id}</td>\n                <td>{$vo.name}</td>\n                <td class=\"td-status\"><span class=\"label radius label-success\">{$vo.create_time}</span></td>\n                <td class=\"td-manage\"><a style=\"text-decoration:none\" class=\"ml-5 o2o_status\"  attr-id=\"{$vo.id}\" attr-status=\"-1\" href=\"javascript:;\" title=\"删除\"><i class=\"Hui-iconfont\">&#xe6e2;</i></a></td>\n            </tr>\n            {/volist}\n            </tbody>\n        </table>\n\n    </div>\n</div>\n<div class=\"cl pd-5 bg-1 bk-gray mt-20 tp5\">{$troubleCate->render()}</div>\n<!--包含头部文件-->\n{include file=\"public/footer\" /}\n<script>\n    var SCOPE ={\n        'listorder_url':\"{:url('category/listorder')}\",\n        'jump_url':\"{:url('category/index')}\",\n        'status_url':\"{:url('category/status')}\",\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "application/admin/view/user/index.html",
    "content": "<!--包含头部文件-->\n{include file=\"public/header\" /}\n<body>\n<nav class=\"breadcrumb\"><i class=\"Hui-iconfont\">&#xe67f;</i> 首页 <span class=\"c-gray en\">&gt;</span> 用户管理 <span class=\"c-gray en\">&gt;</span> 用户列表 <a class=\"btn btn-success radius r\" style=\"line-height:1.6em;margin-top:3px\" href=\"javascript:location.replace(location.href);\" title=\"刷新\" ><i class=\"Hui-iconfont\">&#xe68f;</i></a></nav>\n<div class=\"page-container\">\n    <div class=\"mt-20\">\n        <table class=\"table table-border table-bordered table-bg table-hover table-sort o2o_yfycms\">\n            <thead>\n            <tr class=\"text-c\">\n                <th width=\"40\"><input name=\"\" type=\"checkbox\" value=\"\"></th>\n                <th width=\"80\">ID</th>\n                <th width=\"100\">用户昵称</th>\n                <th width=\"100\">用户头像</th>\n                <th width=\"30\">押金余额</th>\n                <th width=\"150\">充值余额</th>\n                <th width=\"60\">创建时间</th>\n                <th width=\"100\">操作</th>\n            </tr>\n            </thead>\n            <tbody>\n            {volist name=\"user\" id=\"vo\"}\n            <tr class=\"text-c\">\n                <td><input name=\"\" type=\"checkbox\" value=\"{$vo.id}\"></td>\n                <td>{$key+1}</td>\n                <td>{$vo.nickname}</td>\n                <td><img src=\"{$vo.avatarUrl}\" width=\"100\" height=\"100\"></td>\n                <td class=\"td-status\"><span class=\"label label-success radius\">{$vo.guarantee}</span></td>\n                <td class=\"td-status\"><span class=\"label label-success radius\">{$vo.balance}</span></td>\n                <td>{$vo.create_time}</td>\n                <td class=\"td-manage\"><a style=\"text-decoration:none\" class=\"ml-5 o2o_status\"  attr-id=\"{$vo.id}\" attr-status=\"-1\" href=\"javascript:;\" title=\"删除\"><i class=\"Hui-iconfont\">&#xe6e2;</i></a></td>\n            </tr>\n            {/volist}\n            </tbody>\n        </table>\n\n    </div>\n</div>\n<div class=\"cl pd-5 bg-1 bk-gray mt-20 tp5\">{$user->render()}</div>\n<!--包含头部文件-->\n{include file=\"public/footer\" /}\n<script>\n    var SCOPE ={\n        'listorder_url':\"{:url('category/listorder')}\",\n        'jump_url':\"{:url('category/index')}\",\n        'status_url':\"{:url('category/status')}\",\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "application/api/controller/v1/Base.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 9:57\n */\n\nnamespace app\\api\\controller\\v1;\n\n\nuse think\\Controller;\n\nclass Base extends Controller\n{\n\n}"
  },
  {
    "path": "application/api/controller/v1/Bike.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 9:57\n */\n\nnamespace app\\api\\controller\\v1;\n\nuse app\\api\\model\\Bike as BikeModel;\n\nuse app\\api\\validate\\IsMustBePostiveInt;\nuse app\\lib\\exception\\BikeException;\n\nclass Bike extends Base\n{\n    /**\n     * @return false|\\PDOStatement|string|\\think\\Collection\n     * @throws BikeException\n     * 获取单车的位置信息\n     */\n    public function getBicyclePosition() {\n        $bikes = BikeModel::getBicyclePosition();\n        if(!$bikes) {\n           throw new BikeException();\n        }\n        return $bikes;\n    }\n\n\n    /**\n     * @param int $type\n     * @param $id\n     * @return bool\n     * 修改单车的使用状态\n     */\n    public function updateBikeStatus($type = 0,$id) {\n//        (new IsMustBePostiveInt())->goCheck();\n        if($type == 0) {\n            //锁定单车，单车在被使用中\n            $data = [\n                'is_show'=>1\n            ];\n        }elseif ($type == 1) {\n            //释放单车，单车恢复使用\n            $data = [\n                'is_show'=>0\n            ];\n        }elseif ($type == 2) {\n            //单车出现故障\n            $data = [\n                'type'=>1\n            ];\n        }elseif ($type == 3) {\n            //单车恢复正常\n            $data = [\n                'type'=>0\n            ];\n        }\n\n        $res = \\app\\api\\model\\Bike::update($data,['id'=>$id]);\n        if($res) {\n            return true;\n        }else {\n            echo false;\n        }\n    }\n\n    /**\n     * @param $id\n     * @return array|false|\\PDOStatement|string|\\think\\Model\n     * @throws BikeException\n     * 根据单车的ID获取单车的信息\n     */\n    public function getBikeByID($id) {\n//        (new IsMustBePostiveInt())->goCheck();\n        $bike = BikeModel::getBikeByID($id);\n        if(!$bike) {\n            throw new BikeException([\n                'msg'=>'该车牌号不存在'\n            ]);\n        }\n        if($bike['is_show'] == 1){\n            throw new BikeException([\n                'msg'=>'此单车正在被使用',\n                'errorCode'=>10001\n            ]);\n        }\n        if($bike['type'] == 1) {\n            throw new BikeException([\n                'msg'=>'此单车多次被报修，暂不可使用',\n                'errorCode'=>10002\n            ]);\n        }\n        return $bike;\n    }\n}"
  },
  {
    "path": "application/api/controller/v1/Token.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 15:19\n */\n\nnamespace app\\api\\controller\\v1;\n\n\nuse app\\api\\service\\UserToken;\nuse app\\api\\validate\\TokenGet;\nuse app\\lib\\exception\\TokenException;\nuse think\\Cache;\nuse think\\Request;\n\nclass Token extends Base\n{\n    /**\n     * @param $code\n     * @return array\n     * 获取token\n     */\n    public function getToken($code) {\n        (new TokenGet())->goCheck();\n        $user = new UserToken($code);\n        $token = $user->get();\n        return [\n            'token'=>$token\n        ];\n    }\n\n    /**\n     * @return bool\n     * @throws TokenException\n     * 验证token\n     */\n    public function verifyToken() {\n        $token = Request::instance()->header('token');\n        $var = Cache::get($token);\n        if(!$var) {\n            throw new TokenException([\n                'msg'=>'token已经过期',\n                'errorCode'=>10002\n            ]);\n        }\n        return true;\n    }\n}"
  },
  {
    "path": "application/api/controller/v1/TroubleCate.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/8\n * Time: 13:15\n */\n\nnamespace app\\api\\controller\\v1;\n\n\nclass TroubleCate extends Base\n{\n    /**\n     * @return false|\\PDOStatement|string|\\think\\Collection\n     * 获取问题的分类信息\n     */\n    public function getTroubleCate() {\n        $res = new \\app\\api\\model\\TroubleCate();\n        $troubleCate = $res->select();\n        return $troubleCate;\n    }\n}"
  },
  {
    "path": "application/api/controller/v1/TroubleRecord.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/8\n * Time: 11:21\n */\n\nnamespace app\\api\\controller\\v1;\n\n\nuse app\\api\\model\\BikeTrouble;\nuse app\\lib\\exception\\BikeException;\nuse think\\Db;\nuse think\\Exception;\n\nclass TroubleRecord extends Base\n{\n    public function recordTrouble($record) {\n        //分为两种情况，车牌损坏，车牌未损坏\n       //如果有车牌号码，先判断单车是否存在，不存在，抛出异常，\n        //如果存在，写到trouble_record表，根据trouble_record\n        //的id，还有trouble_id写到bike_trouble表，多对多表，全部写入成功之后，\n        //修改bike表的type值，用到事务，要么失败，要么成功\n        $bikeID = $record['inputValue']['num'];\n        //2代表车牌被损坏，看不到车牌号码\n        if(!in_array(2,$record['checkboxValue'])) {\n            if($bikeID) {\n                $bike = new Bike();\n                $bike->getBikeByID($bikeID);\n            }else {\n                throw new BikeException([\n                    'msg'=>'请输入单车编号',\n                    'errorCode'=>10003\n                ]);\n            }\n        }\n        try {\n            Db::startTrans();\n            $address = $record['address'];\n            $uid = \\app\\api\\service\\Token::getCurrentUid();\n            $troubleRecord = new \\app\\api\\model\\TroubleRecord();\n            $troubleRecord->user_id=$uid;\n            $troubleRecord->bike_id=$bikeID;\n            $troubleRecord->longitude=$address['start_long'];\n            $troubleRecord->latitude=$address['start_lati'];\n            $troubleRecord->img=json_encode($record['picUrls']);\n            $troubleRecord->remark=$record['inputValue']['desc'];\n            //更新故障记录表troubleRecord\n            $troubleRecord->save();\n\n            $resID = $troubleRecord->id;\n\n\n            $troublesID = $record['checkboxValue'];\n            $newArr = array();\n            foreach ($troublesID as $k=>$v) {\n                $newArr[$k]['trouble_id'] = $v;\n                $newArr[$k]['record_id'] = $resID;\n            }\n            $bikeTrouble = new BikeTrouble();\n            //更新故障表bikeTrouble表\n            $rel = $bikeTrouble->saveAll($newArr);\n\n            if($bikeID) {\n                //修改单车的状态，发送了故障\n                $bike = new Bike();\n                $bike->updateBikeStatus(2,$bikeID);\n            }\n            if($resID && $rel) {\n                Db::commit();\n            }\n        }catch (Exception $e) {\n            Db::rollback();\n        }\n    }\n}\n"
  },
  {
    "path": "application/api/controller/v1/User.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 16:59\n */\n\nnamespace app\\api\\controller\\v1;\n\nuse app\\api\\model\\Charge;\nuse app\\api\\model\\Record;\nuse app\\api\\service\\Token;\nuse app\\lib\\exception\\UserException;\nuse app\\api\\model\\User as UserModel;\nuse think\\Db;\nuse think\\Exception;\n\nclass User extends Base\n{\n    /**\n     * @return null|static\n     * @throws UserException\n     * 获取用户的信息\n     */\n    public function getUserInfo(){\n        $uid = Token::getCurrentUid();\n        $user = UserModel::get($uid);\n        if(!$user) {\n            throw new UserException();\n        }\n        return $user;\n    }\n\n    /**\n     * @param $guarantee\n     * 充值\n     */\n    public function pay($from,$price) {\n        $type = 1;\n        if($from == 'index') {\n            $type = 0;\n        }else if($from == 'wallet' || $from == 'pay') {\n            $type = 1;\n        }\n        $uid = Token::getCurrentUid();\n        Db::startTrans();\n        try{\n            if($type == 1) {\n                $user = UserModel::get($uid);\n\n                $price = $price + $user->balance;\n                $result = new UserModel();\n                $res = $result->save(['balance'=>$price],['id'=>$uid]);\n            }else {\n                $res = UserModel::update(['guarantee'=>$price],['id'=>$uid]);\n            }\n            $rel = Charge::create([\n                'price'=>$price,\n                'type'=>$type,\n                'user_id'=>$uid\n            ]);\n            if($rel && $res) {\n                Db::commit();\n            }\n        }catch (Exception $e) {\n            Db::rollback();\n            throw new UserException([\n                'msg'=>'充值失败'\n            ]);\n        }\n    }\n\n    /**\n     * @param $price\n     * @return array\n     * 押金退款\n     */\n    public function refund() {\n        $uid = Token::getCurrentUid();\n        $res = UserModel::update(['guarantee'=>0],['id'=>$uid]);\n        $rel = Charge::create([\n            'price'=>0,\n            'type'=>0,\n            'user_id'=>$uid\n        ]);\n        if($rel && $res) {\n            return [\n                'msg'=>'退款成功',\n                'code'=>201\n            ];\n        }\n    }\n\n\n    /**\n     * @param $start_time\n     * @param $bikeID\n     * @param $end_time\n     * @param $start_long\n     * @param $start_lati\n     * @param $end_long\n     * @param $end_lati\n     * @param $price\n     * 用户骑行后记录到数据库\n     */\n    public function record($start_time,$bikeID,$end_time,$start_long,$start_lati,$end_long,$end_lati,$price) {\n        $uid = Token::getCurrentUid();\n        $data = [\n            'start_time'=>$start_time,\n            'end_time'=>$end_time,\n            'start_long'=>$start_long,\n            'start_lati'=>$start_lati,\n            'end_lati'=>$end_lati,\n            'end_long'=>$end_long,\n            'total_price'=>$price,\n            'user_id'=>$uid,\n            'bike_id'=>$bikeID\n        ];\n        Db::startTrans();\n        try {\n            //创建记录\n            $res = Record::create($data);\n\n            //修改用户的余额\n            $user = new UserModel();\n            $userInfo = $user->find($uid);\n            $data = [\n                'balance'=>$userInfo->balance-$price\n            ];\n            $rel = $user->save($data,['id'=>$uid]);\n\n\n            //修改小黄车的状态和位置\n            $bikeData = [\n                'is_show'=>'0',\n                'latitude'=>$end_lati,\n                'longitude'=>$end_long\n            ];\n            $rs = \\app\\api\\model\\Bike::update($bikeData,['id'=>$bikeID]);\n\n\n\n            if($res && $rel && $rs) {\n               echo 'success';\n                Db::commit();\n            }\n        }catch (Exception $e) {\n            Db::rollback();\n        }\n    }\n}"
  },
  {
    "path": "application/api/model/Base.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 10:00\n */\n\nnamespace app\\api\\model;\n\n\nuse think\\Model;\n\nclass Base extends Model\n{\n\n}"
  },
  {
    "path": "application/api/model/Bike.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 9:59\n */\nnamespace app\\api\\model;\nuse think\\Model;\n\nclass Bike extends Model\n{\n\n\n    /**\n     * @return false|\\PDOStatement|string|\\think\\Collection\n     * 获取单车的位置信息\n     */\n    public static function getBicyclePosition() {\n        $data = [\n            'is_show'=>0,\n            'type'=>0\n        ];\n        return self::where($data)->select();\n    }\n\n    /**\n     * @param $id\n     * @return array|false|\\PDOStatement|string|Model\n     * 获取根据ID获取单车的密码\n     */\n    public static function getBikeByID($id) {\n        $data = [\n            'id'=>$id\n        ];\n        return self::where($data)->find();\n    }\n}"
  },
  {
    "path": "application/api/model/BikeTrouble.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/8\n * Time: 15:27\n */\n\nnamespace app\\api\\model;\n\n\nclass BikeTrouble extends Base\n{\n\n}"
  },
  {
    "path": "application/api/model/Charge.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/4\n * Time: 14:04\n */\n\nnamespace app\\api\\model;\n\n\nclass Charge extends Base\n{\n\n}"
  },
  {
    "path": "application/api/model/Record.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/4\n * Time: 20:52\n */\n\nnamespace app\\api\\model;\n\n\nclass Record extends Base\n{\n\n}"
  },
  {
    "path": "application/api/model/TroubleCate.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/8\n * Time: 11:52\n */\n\nnamespace app\\api\\model;\n\n\nclass TroubleCate extends Base\n{\n    protected $hidden = ['create_time','update_time'];\n\n}"
  },
  {
    "path": "application/api/model/TroubleRecord.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/8\n * Time: 11:23\n */\n\nnamespace app\\api\\model;\n\n\nclass TroubleRecord extends Base\n{\n\n}"
  },
  {
    "path": "application/api/model/User.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 15:39\n */\n\nnamespace app\\api\\model;\n\n\nclass User extends Base\n{\n    /**\n     * @param $id\n     * @return array|false|\\PDOStatement|string|\\think\\Model\n     * 根据openid获取用户的信息\n     */\n    public static function getUserByOpenID($id){\n        $data = [\n            'openid'=>$id\n        ];\n        return self::where($data)->find();\n    }\n\n    /**\n     * @param $id\n     * @param $guarantee\n     * @return $this\n     * 修改保证金的金额\n     */\n    public static function updateGuarantee($id,$guarantee) {\n        $data = [\n            'guarantee'=>$guarantee\n        ];\n        return self::update($data,['id'=>$id]);\n    }\n}"
  },
  {
    "path": "application/api/service/Token.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 15:22\n */\n\nnamespace app\\api\\service;\n\n\nuse app\\lib\\exception\\TokenException;\nuse think\\Cache;\nuse think\\Exception;\nuse think\\Request;\n\nclass Token\n{\n    /**\n     * @return string\n     * 生成token\n     */\n    public function generateToken() {\n        $time = $_SERVER['REQUEST_TIME'];\n        $prefix = config('secure.prefix');\n        $str = getRandChars(32);\n        return md5($time.$prefix.$str);\n    }\n\n\n    /**\n     * @param $key\n     * @return mixed\n     * @throws Exception\n     * @throws TokenException\n     * 根据变量获取缓存token里面的内容，例如：uid，openid,session_key\n     */\n    public static function getCurrentTokenVar($key) {\n        //获取token\n        $token = Request::instance()->header('token');\n        $vars = Cache::get($token);\n        if(!$vars) {\n            throw new TokenException();\n        }else {\n            if(!is_array($vars)) {\n                $vars = json_decode($vars,true);\n            }\n            if(array_key_exists($key,$vars)) {\n                return $vars[$key];\n            }else {\n                throw new Exception(['尝试获取token的变量不存在']);\n            }\n        }\n    }\n    public static function getCurrentUid() {\n        $uid = self::getCurrentTokenVar('id');\n        return $uid;\n    }\n\n\n}"
  },
  {
    "path": "application/api/service/UserToken.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 15:21\n */\n\nnamespace app\\api\\service;\n\n\nuse app\\api\\model\\User;\nuse app\\lib\\exception\\WxChatException;\nuse app\\lib\\exception\\WxException;\nuse think\\Exception;\n\nclass UserToken extends Token\n{\n    protected $app_id;\n\n    protected $app_secret;\n\n    protected $wx_login_url;\n\n    public $code;\n    protected $nickname;\n\n    public function __construct($code)\n    {\n        $this->code = $code;\n        $this->app_id = config('wx.app_id');\n        $this->app_secret = config('wx.app_secret');\n        $this->wx_login_url = sprintf(config('wx.login_url'),$this->app_id,$this->app_secret,$code);\n    }\n\n    public function get() {\n        $result = curl_get($this->wx_login_url);\n        $result = json_decode($result,true);\n        if(!$result) {\n            throw new Exception([\n                'msg'=>'获取openID失败，微信内部错误'\n            ]);\n        }else {\n            if(array_key_exists('errcode',$result)){\n                $this->processLoginError($result);\n            }else {\n                return $this->grantToken($result);\n            }\n        }\n    }\n\n    /**\n     * @param $result\n     * @return string\n     * 分配token\n     */\n    public function grantToken($result) {\n        $openId = $result['openid'];\n        $user = User::getUserByOpenID($openId);\n        if($user) {\n            $userId = $user->id;\n        }else {\n            $userId = $this->newUser($openId);\n        }\n        $user = User::get($userId);\n        return $this->saveToCache($user);\n    }\n\n    /**\n     * @param $user\n     * @return string\n     * @throws Exception\n     * 保存到缓存中\n     */\n    public function saveToCache($user) {\n        $value = json_encode($user);\n        $key = $this->generateToken();\n        $expire_in = config('setting.token_expire_in');\n        $res = cache($key,$value,$expire_in);\n        if(!$res) {\n            throw new Exception([\n                'msg'=>'缓存失败，请查看系统日志'\n            ]);\n        }\n        return $key;\n    }\n\n    /**\n     * @param $openId\n     * @return mixed\n     * 创造新的用户\n     */\n    public function newUser($openId) {\n        $user = User::create(['openid'=>$openId]);\n        return $user->id;\n    }\n\n    /**\n     * @param $result\n     * @throws WxException\n     * 处理微信登录的错误\n     */\n    public function processLoginError($result) {\n        throw new WxChatException([\n            'msg'=>$result['errmsg'],\n            'errCode'=>$result['errcode']\n        ]);\n    }\n\n}"
  },
  {
    "path": "application/api/validate/AddressNews.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/7/1\n * Time: 14:29\n */\n\nnamespace app\\api\\validate;\n\n\nclass AddressNews extends BaseValidate\n{\n    protected $rule = [\n        'name'=>'require|isNotEmpty',\n        'mobile'=>'require',\n        'city'=>'require|isNotEmpty',\n        'country'=>'require|isNotEmpty',\n        'detail'=>'require|isNotEmpty',\n        'province'=>'require|isNotEmpty',\n    ];\n}"
  },
  {
    "path": "application/api/validate/AppTokenGet.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/8/6\n * Time: 19:21\n */\n\nnamespace app\\api\\validate;\n\n\nclass AppTokenGet extends BaseValidate\n{\n    protected $rule = [\n        'ac'=>\"require\",\n        'se'=>'require'\n    ];\n}"
  },
  {
    "path": "application/api/validate/BaseValidate.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: Administrator\n * Date: 2017/5/29\n * Time: 9:03\n */\n\nnamespace app\\api\\validate;\n\n\nuse app\\lib\\exception\\ParameterException;\nuse think\\Exception;\nuse think\\Request;\nuse think\\Validate;\n\nclass BaseValidate extends Validate\n{\n    /**\n     * @return bool\n     * @throws ParameterException\n     * 验证器的入口方法\n     */\n    public function goCheck() {\n        //获取实例接口\n        $request = Request::instance();\n        //获取所有参数\n         $param = $request->param();\n         $result = $this->batch()->check($param);\n\n             if(!$result) {\n                 $e = new ParameterException([\n                     'msg' => $this->error\n                 ]);\n                 throw $e;\n             }\n                 return true;\n\n    }\n\n    /**\n     * @param $value\n     * @param string $rule\n     * @param string $data\n     * @param string $filed\n     * @return bool\n     * 判断参数是否是整数\n     */\n    protected function isPostiveInt($value,$rule = '',$data = '',$filed = '')\n    {\n        if (is_numeric($value) && is_int($value + 0) && is_int($value + 0) > 0) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @param $value\n     * @param string $rule\n     * @param string $data\n     * @param string $filed\n     * @return bool\n     * 判断参数是否为空\n     */\n    public function isNotEmpty($value,$rule = '',$data = '',$filed = ''){\n        if(empty($value)) {\n            return false;\n        }else {\n            return true;\n        }\n    }\n\n    /**\n     * @param $arrays\n     * @return array\n     * @throws ParameterException\n     * 根据规则获取参数数据\n     */\n    public function getDataByRule($arrays) {\n        if(array_key_exists('uid',$arrays) || array_key_exists('user_id',$arrays)) {\n            throw new ParameterException([\n                'msg'=>'传递了非法参数user_id或者uid'\n            ]);\n        }\n        $newArr = [];\n        foreach ($this->rule as $key=>$value) {\n            $newArr[$key] = $arrays[$key];\n        }\n        return $newArr;\n    }\n\n}"
  },
  {
    "path": "application/api/validate/Count.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/6/23\n * Time: 20:29\n */\n\nnamespace app\\api\\validate;\n\n\nclass Count extends BaseValidate\n{\n    protected $rule = [\n        'count'=>'isPostiveInt|between:1,15'\n    ];\n}"
  },
  {
    "path": "application/api/validate/IDCollection.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/6/21\n * Time: 22:57\n */\n\nnamespace app\\api\\validate;\n\n\nclass IDCollection extends BaseValidate\n{\n    protected $rule = [\n        'ids'=>'require|checkIDs'\n    ];\n\n    protected $message = [\n        'ids'=>'ids是以逗号分隔的正整数'\n    ];\n\n    protected function checkIDs($value) {\n        $values = explode(',',$value);\n        if(empty($values)) {\n            return false;\n        }\n        foreach ($values as $id) {\n            if(!$this->isPostiveInt($id)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n}"
  },
  {
    "path": "application/api/validate/IsMustBePostiveInt.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: Administrator\n * Date: 2017/5/28\n * Time: 22:29\n */\n\nnamespace app\\api\\validate;\n\n\nuse think\\Validate;\n\nclass IsMustBePostiveInt extends BaseValidate\n{\n    protected $rule = [\n        'id'=>'require|isPostiveInt',\n    ];\n\n    protected $message = [\n        'id'=>'id必须是正整数'\n    ];\n\n\n\n\n}"
  },
  {
    "path": "application/api/validate/OrderPlace.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/7/2\n * Time: 9:56\n */\n\nnamespace app\\api\\validate;\n\n\nuse app\\lib\\exception\\ParameterException;\n\nclass OrderPlace extends  BaseValidate\n{\n    protected $rule = [\n        'products'=>'checkProducts'\n    ];\n\n    protected $singleRule = [\n        'product_id'=>'require|isPostiveInt',\n        'count'=>'require|isPostiveInt'\n    ];\n\n    public function checkProducts($values) {\n        if(!is_array($values)) {\n            throw new ParameterException([\n                'msg'=>'参数不合法'\n            ]);\n        }\n        if(empty($values)) {\n            throw new ParameterException([\n                'msg'=>'商品列表不能为空'\n            ]);\n        }\n        foreach($values as $value) {\n            $this->checkProduct($value);\n        }\n        return true;\n    }\n\n    public function checkProduct($value) {\n        $validate = new BaseValidate($this->singleRule);\n        $result = $validate->check($value);\n        if(!$result) {\n            throw new ParameterException([\n                'msg'=>'商品列表参数错误'\n            ]);\n        }\n    }\n}"
  },
  {
    "path": "application/api/validate/PagingParameter.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/7/15\n * Time: 18:35\n */\n\nnamespace app\\api\\validate;\n\n\nclass PagingParameter extends BaseValidate\n{\n    protected $rule = [\n        'page'=>'require|isPostiveInt',\n        'size'=>'isPostiveInt'\n    ];\n\n    protected $message = [\n        'page'=>'分页参数必须是正整数',\n        'size'=>'分页参数必须是正整数'\n    ];\n}"
  },
  {
    "path": "application/api/validate/TokenGet.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/6/25\n * Time: 14:17\n */\n\nnamespace app\\api\\validate;\n\n\nclass TokenGet extends BaseValidate\n{\n    protected $rule = [\n        'code'=>'require|isNotEmpty'\n    ];\n\n    protected $message = [\n        'code'=>'没有code值还想获取token值做梦哦'\n    ];\n}"
  },
  {
    "path": "application/command.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nreturn [];\n"
  },
  {
    "path": "application/common.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 流年 <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n\n\n/**\n * @param $url\n * @param $type 1|post方式 0|get方式\n * @param array $data\n */\nfunction doCurl($url,$type = 0,$data=[]) {\n    $cu = curl_init(); //初始化\n    //设置选项\n    curl_setopt($cu,CURLOPT_URL,$url); //设置url\n    curl_setopt($cu,CURLOPT_RETURNTRANSFER,1); //信息以文件流的方式保存，而不是直接输出\n    curl_setopt($cu,CURLOPT_HEADER,0); //不包括header头部信息\n    if($type == 1) {\n        //post\n        curl_setopt($cu,CURLOPT_POST,1);\n        curl_setopt($cu,CURLOPT_POSTFIELDS,$data);\n    }\n    //执行并获取内容\n    $output = curl_exec($cu);\n    //释放curl句柄\n    curl_close($cu);\n    return $output;\n}\n// 应用公共文件\n/**\n * @param $url\n * @param int $httpCode\n * @return mixed\n * 获取网咯资源\n */\nfunction curl_get($url,&$httpCode = 0) {\n    $curl = curl_init();\n    curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址\n    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回\n    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查\n    curl_setopt($curl,CURLOPT_CONNECTTIMEOUT,10);\n    $file_contents = curl_exec($curl);\n    $httpCode = curl_getinfo($curl,CURLINFO_HTTP_CODE);\n    curl_close($curl);\n    return $file_contents;\n}\n\n/**\n * @param $length\n * @return string\n * 获取随机的字符串\n */\nfunction getRandChars($length) {\n    $str = '';\n    $strPol = 'QWERTYUIOPASDFGHJKLXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm';\n    $max =strlen($strPol)-1;\n    for($i=0;$i<$length;$i++) {\n        $str.=$strPol[rand(0,$max)];\n    }\n    return $str;\n}\n\n/**\n * @param $status\n * @param $message\n * @param array $data\n * 公用的展示方法\n */\nfunction show($status,$message,$data =array()){\n    $result = [\n        'status'=>$status,\n        'message'=>$message,\n        'data'=>$data\n    ];\n    exit(json_encode($result));\n}\n\n/**\n * @param $code\n * @return string\n * 车辆的使用情况\n */\nfunction userStatus($code) {\n    if($code == 0) {\n        return '未使用';\n    }else {\n        return \"使用中\";\n    }\n}\n\n/**\n * @param $code\n * @return string\n * 车辆是否发生故障\n */\nfunction troubleStatus($code) {\n    if($code == 0) {\n        return \"正常\";\n    }else {\n        return \"故障\";\n    }\n}\n\n/**\n * @param $value\n * @return string\n * 单车的修理状态\n */\n function getStatusAttr($value) {\n    if($value == 0) {\n        return $value = '待修理';\n    }elseif($value == 1) {\n        return $value = '已修理';\n    }\n}\n\n"
  },
  {
    "path": "application/config.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nreturn [\n    // +----------------------------------------------------------------------\n    // | 应用设置\n    // +----------------------------------------------------------------------\n\n    // 应用命名空间\n    'app_namespace'          => 'app',\n    // 应用调试模式\n    'app_debug'              => true,\n    // 应用Trace\n    'app_trace'              => false,\n    // 应用模式状态\n    'app_status'             => '',\n    // 是否支持多模块\n    'app_multi_module'       => true,\n    // 入口自动绑定模块\n    'auto_bind_module'       => false,\n    // 注册的根命名空间\n    'root_namespace'         => [],\n    // 扩展函数文件\n    'extra_file_list'        => [THINK_PATH . 'helper' . EXT],\n    // 默认输出类型\n    'default_return_type'    => 'html',\n    // 默认AJAX 数据返回格式,可选json xml ...\n    'default_ajax_return'    => 'json',\n    // 默认JSONP格式返回的处理方法\n    'default_jsonp_handler'  => 'jsonpReturn',\n    // 默认JSONP处理方法\n    'var_jsonp_handler'      => 'callback',\n    // 默认时区\n    'default_timezone'       => 'PRC',\n    // 是否开启多语言\n    'lang_switch_on'         => false,\n    // 默认全局过滤方法 用逗号分隔多个\n    'default_filter'         => '',\n    // 默认语言\n    'default_lang'           => 'zh-cn',\n    // 应用类库后缀\n    'class_suffix'           => false,\n    // 控制器类后缀\n    'controller_suffix'      => false,\n\n    // +----------------------------------------------------------------------\n    // | 模块设置\n    // +----------------------------------------------------------------------\n\n    // 默认模块名\n    'default_module'         => 'index',\n    // 禁止访问模块\n    'deny_module_list'       => ['common'],\n    // 默认控制器名\n    'default_controller'     => 'Index',\n    // 默认操作名\n    'default_action'         => 'index',\n    // 默认验证器\n    'default_validate'       => '',\n    // 默认的空控制器名\n    'empty_controller'       => 'Error',\n    // 操作方法后缀\n    'action_suffix'          => '',\n    // 自动搜索控制器\n    'controller_auto_search' => false,\n\n    // +----------------------------------------------------------------------\n    // | URL设置\n    // +----------------------------------------------------------------------\n\n    // PATHINFO变量名 用于兼容模式\n    'var_pathinfo'           => 's',\n    // 兼容PATH_INFO获取\n    'pathinfo_fetch'         => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],\n    // pathinfo分隔符\n    'pathinfo_depr'          => '/',\n    // URL伪静态后缀\n    'url_html_suffix'        => 'html',\n    // URL普通方式参数 用于自动生成\n    'url_common_param'       => false,\n    // URL参数方式 0 按名称成对解析 1 按顺序解析\n    'url_param_type'         => 0,\n    // 是否开启路由\n    'url_route_on'           => true,\n    // 路由使用完整匹配\n    'route_complete_match'   => false,\n    // 路由配置文件（支持配置多个）\n    'route_config_file'      => ['route'],\n    // 是否强制使用路由\n    'url_route_must'         => false,\n    // 域名部署\n    'url_domain_deploy'      => false,\n    // 域名根，如thinkphp.cn\n    'url_domain_root'        => '',\n    // 是否自动转换URL中的控制器和操作名\n    'url_convert'            => true,\n    // 默认的访问控制器层\n    'url_controller_layer'   => 'controller',\n    // 表单请求类型伪装变量\n    'var_method'             => '_method',\n    // 表单ajax伪装变量\n    'var_ajax'               => '_ajax',\n    // 表单pjax伪装变量\n    'var_pjax'               => '_pjax',\n    // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则\n    'request_cache'          => false,\n    // 请求缓存有效期\n    'request_cache_expire'   => null,\n    // 全局请求缓存排除规则\n    'request_cache_except'   => [],\n\n    // +----------------------------------------------------------------------\n    // | 模板设置\n    // +----------------------------------------------------------------------\n\n    'template'               => [\n        // 模板引擎类型 支持 php think 支持扩展\n        'type'         => 'Think',\n        // 模板路径\n        'view_path'    => '',\n        // 模板后缀\n        'view_suffix'  => 'html',\n        // 模板文件名分隔符\n        'view_depr'    => DS,\n        // 模板引擎普通标签开始标记\n        'tpl_begin'    => '{',\n        // 模板引擎普通标签结束标记\n        'tpl_end'      => '}',\n        // 标签库标签开始标记\n        'taglib_begin' => '{',\n        // 标签库标签结束标记\n        'taglib_end'   => '}',\n    ],\n\n    // 视图输出字符串内容替换\n    'view_replace_str'       => [],\n    // 默认跳转页面对应的模板文件\n    'dispatch_success_tmpl'  => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',\n    'dispatch_error_tmpl'    => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',\n\n    // +----------------------------------------------------------------------\n    // | 异常及错误设置\n    // +----------------------------------------------------------------------\n\n    // 异常页面的模板文件\n    'exception_tmpl'         => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',\n\n    // 错误显示信息,非调试模式有效\n    'error_message'          => '页面错误！请稍后再试～',\n    // 显示错误信息\n    'show_error_msg'         => false,\n    // 异常处理handle类 留空使用 \\think\\exception\\Handle\n    'exception_handle'       => 'app\\lib\\exception\\ExceptionHandler',\n\n    // +----------------------------------------------------------------------\n    // | 日志设置\n    // +----------------------------------------------------------------------\n\n    'log'                    => [\n        // 日志记录方式，内置 file socket 支持扩展\n        'type'  => 'File',\n        // 日志保存目录\n        'path'  => LOG_PATH,\n        // 日志记录级别\n        'level' => ['error'],\n    ],\n\n    // +----------------------------------------------------------------------\n    // | Trace设置 开启 app_trace 后 有效\n    // +----------------------------------------------------------------------\n    'trace'                  => [\n        // 内置Html Console 支持扩展\n        'type' => 'Html',\n    ],\n\n    // +----------------------------------------------------------------------\n    // | 缓存设置\n    // +----------------------------------------------------------------------\n\n    'cache'                  => [\n        // 驱动方式\n        'type'   => 'File',\n        // 缓存保存目录\n        'path'   => CACHE_PATH,\n        // 缓存前缀\n        'prefix' => '',\n        // 缓存有效期 0表示永久缓存\n        'expire' => 0,\n    ],\n\n    // +----------------------------------------------------------------------\n    // | 会话设置\n    // +----------------------------------------------------------------------\n\n    'session'                => [\n        'id'             => '',\n        // SESSION_ID的提交变量,解决flash上传跨域\n        'var_session_id' => '',\n        // SESSION 前缀\n        'prefix'         => '',\n        // 驱动方式 支持redis memcache memcached\n        'type'           => 'memcached',\n        // 是否自动开启 SESSION\n        'auto_start'     => true,\n    ],\n\n    // +----------------------------------------------------------------------\n    // | Cookie设置\n    // +----------------------------------------------------------------------\n    'cookie'                 => [\n        // cookie 名称前缀\n        'prefix'    => '',\n        // cookie 保存时间\n        'expire'    => 0,\n        // cookie 保存路径\n        'path'      => '/',\n        // cookie 有效域名\n        'domain'    => '',\n        //  cookie 启用安全传输\n        'secure'    => false,\n        // httponly设置\n        'httponly'  => '',\n        // 是否使用 setcookie\n        'setcookie' => true,\n    ],\n\n    //分页配置\n    'paginate'               => [\n        'type'      => 'bootstrap',\n        'var_page'  => 'page',\n        'list_rows' => 15,\n    ],\n];\n"
  },
  {
    "path": "application/database.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nreturn [\n    // 数据库类型\n    'type'            => 'mysql',\n    // 服务器地址\n    'hostname'        => '127.0.0.1',\n    // 数据库名\n    'database'        => 'ofo',\n    // 用户名\n    'username'        => 'root',\n    // 密码\n    'password'        => 'root',\n    // 端口\n    'hostport'        => '',\n    // 连接dsn\n    'dsn'             => '',\n    // 数据库连接参数\n    'params'          => [],\n    // 数据库编码默认采用utf8\n    'charset'         => 'utf8',\n    // 数据库表前缀\n    'prefix'          => '',\n    // 数据库调试模式\n    'debug'           => true,\n    // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)\n    'deploy'          => 0,\n    // 数据库读写是否分离 主从式有效\n    'rw_separate'     => false,\n    // 读写分离后 主服务器数量\n    'master_num'      => 1,\n    // 指定从服务器序号\n    'slave_no'        => '',\n    // 是否严格检查字段是否存在\n    'fields_strict'   => true,\n    // 数据集返回类型\n    'resultset_type'  => 'array',\n    // 自动写入时间戳字段\n    'auto_timestamp'  => true,\n    // 时间字段取出后的默认时间格式\n    'datetime_format' => 'Y-m-d H:i:s',\n    // 是否需要进行SQL性能分析\n    'sql_explain'     => false,\n];\n"
  },
  {
    "path": "application/extra/map.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/12\n * Time: 18:01\n */\nreturn [\n    'ak'=>'ORFYUgrDDYS5ralxOkh5KS8gNG30mVzy',\n    'baidu_map_url'=>'http://api.map.baidu.com/',\n    'geocorder'=>'geocoder/v2/',\n];"
  },
  {
    "path": "application/extra/pagination.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/12\n * Time: 16:11\n */\nreturn [\n    'page'=>1,\n    'list_rows'=>2,\n    'user'=>[\n        'page'=>1,\n        'list_row'=>10\n    ],\n    'charge'=>[\n        'page'=>1,\n        'list_row'=>15\n    ]\n];"
  },
  {
    "path": "application/extra/queue.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nreturn [\n    'connector' => 'Sync'\n];"
  },
  {
    "path": "application/extra/redis.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 16:04\n */\nreturn [\n    'ip'=>'127.0.0.1',\n    'port'=>6379\n];"
  },
  {
    "path": "application/extra/secure.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 15:59\n */\nreturn [\n    'profix'=>'yfyjsz'\n];"
  },
  {
    "path": "application/extra/setting.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/6/20\n * Time: 21:08\n */\nreturn [\n    'token_expire_in'=>7200\n];"
  },
  {
    "path": "application/extra/tx.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/16\n * Time: 11:05\n */\n/**\n *\n * 腾讯地图的相关配置\n */\nreturn [\n    'tx_url'=>'http://apis.map.qq.com/ws/geocoder/v1/',\n    'key'=>'CKYBZ-ED2CX-XHM4T-7TSWJ-B6RZO-RMB7H'\n];"
  },
  {
    "path": "application/extra/wx.php",
    "content": "<?php\n\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/6/25\n * Time: 15:46\n */\nreturn [\n    'app_id'=>'wxa1352690d1c0904f',\n    'app_secret'=>'55554158847ba36f944a385cf8d4cb4a',\n    'login_url'=>\"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code\"\n];"
  },
  {
    "path": "application/index/controller/Index.php",
    "content": "<?php\nnamespace app\\index\\controller;\n\nclass Index\n{\n    public function index()\n    {\n        return '<style type=\"text/css\">*{ padding: 0; margin: 0; } .think_default_text{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: \"Century Gothic\",\"Microsoft yahei\"; color: #333;font-size:18px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style=\"padding: 24px 48px;\"> <h1>:)</h1><p> ThinkPHP V5<br/><span style=\"font-size:30px\">十年磨一剑 - 为API开发设计的高性能框架</span></p><span style=\"font-size:22px;\">[ V5.0 版本由 <a href=\"http://www.qiniu.com\" target=\"qiniu\">七牛云</a> 独家赞助发布 ]</span></div><script type=\"text/javascript\" src=\"http://tajs.qq.com/stats?sId=9347272\" charset=\"UTF-8\"></script><script type=\"text/javascript\" src=\"http://ad.topthink.com/Public/static/client.js\"></script><thinkad id=\"ad_bd568ce7058a1091\"></thinkad>';\n    }\n}\n"
  },
  {
    "path": "application/lib/exception/BaseException.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: Administrator\n * Date: 2017/5/29\n * Time: 15:46\n */\n\nnamespace app\\lib\\exception;\n\n\nuse think\\Exception;\n\nclass BaseException extends Exception\n{\n    //http状态码\n    public $code = 400;\n\n    //错误信息\n    public $msg = '参数错误';\n\n    //错误码\n    public $errorCode = 40000;\n\n    /**\n     * BaseException constructor.\n     * @param array $param\n     * 构造函数\n     */\n    public function __construct($param = [])\n    {\n        if(!is_array($param)) {\n            return  ;\n        }\n        if(array_key_exists('code',$param)) {\n            $this->code = $param['code'];\n        }\n        if(array_key_exists('msg',$param)) {\n            $this->msg = $param['msg'];\n        }\n        if(array_key_exists('errorCode',$param)) {\n            $this->errorCode= $param['errorCode'];\n        }\n    }\n}"
  },
  {
    "path": "application/lib/exception/BikeException.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/9/1\n * Time: 10:21\n */\n\nnamespace app\\lib\\exception;\n\n\nclass BikeException extends BaseException\n{\n    public $code = 401;\n\n    public $msg = '单车不存在';\n\n    public $errorCode = 10000;\n}"
  },
  {
    "path": "application/lib/exception/ExceptionHandler.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: Administrator\n * Date: 2017/5/29\n * Time: 15:44\n */\n\nnamespace app\\lib\\exception;\n\n\nuse Exception;\nuse think\\Config;\nuse think\\exception\\Handle;\nuse think\\Log;\nuse think\\Request;\n\nclass ExceptionHandler extends Handle\n{\n    private $code;\n    private $msg;\n    private $errorCode;\n\n    //请求资源的url\n\n    /**\n     * @param Exception $e\n     * @return \\think\\response\\Json\n     * 重写tp5的异常处理方法,自定义异常处理\n     */\n    public function render(Exception $e)\n    {\n        //判断是什么异常类型\n        if($e instanceof BaseException) {\n            //自定义的异常,用户行为导致的异常\n            $this->code = $e->code;\n            $this->msg = $e->msg;\n            $this->errorCode = $e->errorCode;\n        }else {\n            //服务器内部异常\n            //Config::get('app_debug');\n            if(config('app_debug')) {\n                //return default error page\n                return parent::render($e);\n            }else {\n                $this->code = '500';\n                $this->msg = '服务器内部异常，不想告诉你!';\n                $this->errorCode = '999';\n                $this->recordErrorLog($e);\n            }\n\n        }\n        $request = Request::instance();\n        $result = [\n            'code'=>$this->code,\n            'msg'=>$this->msg,\n            'errorCode'=>$this->errorCode,\n            'request_url'=>$request->url()\n        ];\n\n        return json($result,$this->code);\n    }\n\n    /**\n     * @param Exception $e\n     * 记录错误异常，用户导致的异常无需记录日志，意义不大，\n     * 服务器内部产生的异常需要记录到日志文件，排错\n     * 生产环境下，只能通过日志来排查错误，测试环境下可以直接打断点排查错误\n     */\n    protected function recordErrorLog(Exception $e) {\n        Log::init([\n            'type'=>'File',\n            'path'=>LOG_PATH,\n            'level'=>['error']\n        ]);\n        Log::record($e->getMessage(),'error');\n    }\n\n}"
  },
  {
    "path": "application/lib/exception/ParameterException.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: Administrator\n * Date: 2017/5/30\n * Time: 0:07\n */\n\nnamespace app\\lib\\exception;\n\n\nclass ParameterException extends BaseException\n{\n    public $code = 400;\n\n    public $msg = '参数错误';\n\n    public $errorCode = 10000;\n}"
  },
  {
    "path": "application/lib/exception/SuccessMessage.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/7/1\n * Time: 15:17\n */\n\nnamespace app\\lib\\exception;\n\n\nclass SuccessMessage\n{\n    public $code = 201;\n    public $msg ='ok';\n    public $errorCode = 0;\n}"
  },
  {
    "path": "application/lib/exception/TokenException.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/6/29\n * Time: 11:34\n */\n\nnamespace app\\lib\\exception;\n\n\nclass TokenException extends BaseException\n{\n    public $code = 401;\n    public $errorCode = 10001;\n    public $msg = 'token已过期或者无效toekn';\n}"
  },
  {
    "path": "application/lib/exception/UserException.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/7/1\n * Time: 15:12\n */\n\nnamespace app\\lib\\exception;\n\n\nclass UserException extends BaseException\n{\n    public $code = 401;\n    public $msg = '用户不存在';\n    public $errorCode = 60001;\n}"
  },
  {
    "path": "application/lib/exception/WxChatException.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: 12810\n * Date: 2017/6/26\n * Time: 23:49\n */\n\nnamespace app\\lib\\exception;\n\n\nclass WxChatException extends BaseException\n{\n    public $code = 400;\n    public $errorCode = 50000;\n    public $msg = '微信内部错误';\n}"
  },
  {
    "path": "application/route.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nuse think\\Route;\n//bike\nRoute::post('api/:version/bike/status','api/:version.bike/updateBikeStatus');\nRoute::get('api/:version/bike','api/:version.bike/getBicyclePosition');\nRoute::post('api/:version/bike','api/:version.bike/getBikeByID');\n\n\n//token\nRoute::post('api/:version/token/user','api/:version.token/getToken');\nRoute::post('api/:version/token/verify','api/:version.token/verifyToken');\n\n//user\nRoute::post('api/:version/user/wallet','api/:version.user/getUserInfo');\nRoute::post('api/:version/user/pay','api/:version.user/pay');\nRoute::post('api/:version/user/refund','api/:version.user/refund');\nRoute::post('api/:version/user/record','api/:version.user/record');\n\n//trouble\nRoute::post('api/:version/trouble/record','api/:version.TroubleRecord/recordTrouble');\nRoute::post('api/:version/trouble','api/:version.troubleCate/getTroubleCate');\n"
  },
  {
    "path": "application/tags.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n// 应用行为扩展定义文件\nreturn [\n    // 应用初始化\n    'app_init'     => [],\n    // 应用开始\n    'app_begin'    => [],\n    // 模块初始化\n    'module_init'  => [],\n    // 操作开始执行\n    'action_begin' => [],\n    // 视图内容过滤\n    'view_filter'  => [],\n    // 日志写入\n    'log_write'    => [],\n    // 应用结束\n    'app_end'      => [],\n];\n"
  },
  {
    "path": "build.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nreturn [\n    // 生成应用公共文件\n    '__file__' => ['common.php', 'config.php', 'database.php'],\n\n    // 定义demo模块的自动生成 （按照实际定义的文件名生成）\n    'demo'     => [\n        '__file__'   => ['common.php'],\n        '__dir__'    => ['behavior', 'controller', 'model', 'view'],\n        'controller' => ['Index', 'Test', 'UserType'],\n        'model'      => ['User', 'UserType'],\n        'view'       => ['index/index'],\n    ],\n    // 其他更多的模块定义\n];\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"topthink/think\",\n    \"description\": \"the new thinkphp framework\",\n    \"type\": \"project\",\n    \"keywords\": [\n        \"framework\",\n        \"thinkphp\",\n        \"ORM\"\n    ],\n    \"homepage\": \"http://thinkphp.cn/\",\n    \"license\": \"Apache-2.0\",\n    \"authors\": [\n        {\n            \"name\": \"liu21st\",\n            \"email\": \"liu21st@gmail.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.4.0\",\n        \"topthink/framework\": \"^5.0\"\n    },\n    \"extra\": {\n        \"think-path\": \"thinkphp\"\n    },\n    \"config\": {\n        \"preferred-install\": \"dist\"\n    }\n}\n"
  },
  {
    "path": "extend/.gitignore",
    "content": "!.gitignore"
  },
  {
    "path": "extend/Map.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/12\n * Time: 17:59\n */\n\n/*百度地图获取地址封装*/\n\nclass Map\n{\n    /**\n     * @param $address\n     * @return mixed\n     * 根据地址获取经纬度\n     */\n    public static function getLngLat($address)\n    {\n        $data = [\n            'address' => $address,\n            'ak' => config('map.ak'),\n            'output' => 'json'\n        ];\n        $url = config('map.baidu_map_url') . config('map.geocorder') . '?' . http_build_query($data);\n        $result = doCurl($url);\n        $result = json_decode($result, true);\n        return $result;\n    }\n\n    /**\n     * @param $lng\n     * @param $lat\n     * @return mixed\n     * 根据经纬度获取单车的地址\n     */\n    public static function getAddress($lng, $lat)\n    {\n        $data = [\n            'location' => $lng . ',' . $lat,\n            'ak' => config('map.ak'),\n            'output' => 'json'\n        ];\n        $url = config('map.baidu_map_url') . config('map.geocorder') . '?' . http_build_query($data);\n        $result = curl_get($url);\n        $result = json_decode($result, true);\n        return $result;\n    }\n}"
  },
  {
    "path": "extend/My/RedisPackage.php",
    "content": "<?php\nnamespace My;\n\nclass RedisPackage\n{\n    protected static $handler = null;\n    protected $options = [\n    'host' => '118.31.12.220',\n    'port' => 6379,\n    'password' => '',\n    'select' => 0,\n    'timeout' => 0,\n    'expire' => 0,\n    'persistent' => false,\n    'prefix' => '',\n    ];\n    public function __construct($options = [])\n    {\n        if (!extension_loaded('redis')) {   //判断是否有扩展(如果你的apache没reids扩展就会抛出这个异常)\n        throw new \\BadFunctionCallException('not support: redis');\n    }\n        if (!empty($options)) {\n        $this->options = array_merge($this->options, $options);\n    }\n        $func = $this->options['persistent'] ? 'pconnect' : 'connect';     //判断是否长连接\n        self::$handler = new \\Redis;\n        self::$handler->$func($this->options['host'], $this->options['port'], $this->options['timeout']);\n\n        if ('' != $this->options['password']) {\n        self::$handler->auth($this->options['password']);\n    }\n\n        if (0 != $this->options['select']) {\n        self::$handler->select($this->options['select']);\n    }\n}\n\n    /**\n    * 写入缓存\n    * @param string $key 键名\n    * @param string $value 键值\n    * @param int $exprie 过期时间 0:永不过期\n    * @return bool\n    */\n    public static function set($key, $value, $exprie = 0)\n    {\n        if ($exprie == 0) {\n         $set = self::$handler->set($key, $value);\n    } else {\n        $set = self::$handler->setex($key, $exprie, $value);\n    }\n        return $set;\n}\n\n    /**\n     * @param $key\n     * 删除缓存\n     */\n    public static function delete($key) {\n        self::$handler->delete($key);\n    }\n\n/**\n* 读取缓存\n* @param string $key 键值\n* @return mixed\n*/\n    public static function get($key)\n    {\n        $fun = is_array($key) ? 'Mget' : 'get';\n        return self::$handler->{$fun}($key);\n    }\n\n    /**\n    * 获取值长度\n    * @param string $key\n    * @return int\n    */\n    public static function lLen($key)\n    {\n        return self::$handler->lLen($key);\n    }\n\n    /**\n    * 将一个或多个值插入到列表头部\n    * @param $key\n    * @param $value\n    * @return int\n    */\n    public static function LPush($key, $value, $value2 = null, $valueN = null)\n        {\n            return self::$handler->lPush($key, $value, $value2, $valueN);\n        }\n\n    /**\n    * 移出并获取列表的第一个元素\n    * @param string $key\n    * @return string\n    */\n    public static function lPop($key)\n    {\n        return self::$handler->lPop($key);\n    }\n}"
  },
  {
    "path": "extend/TxMap.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/16\n * Time: 11:02\n */\n\n/**\n * 腾讯地图根据经纬度获取地址或者根据地址获取经纬度\n */\nclass TxMap\n{\n    /**\n     * @param $address\n     * @return mixed\n     * 根据地址获取经纬度\n     */\n    public static function getLngLat($address){\n        $data = [\n            'address'=>$address,\n            'key'=>config('tx.key')\n        ];\n        $url = config('tx.tx_url').'?'.http_build_query($data);\n        $result = doCurl($url);\n        return json_decode($result,true);\n    }\n    /**\n     * @param $lng\n     * @param $lat\n     * @return mixed\n     * 根据经纬度获取地址\n     */\n    public static function getAddress($lng,$lat){\n        $data = [\n            'location'=>$lat.','.$lng,\n            'key'=>config('tx.key'),\n            'get_poi'=>0\n        ];\n        $url = config('tx.tx_url').'?'.http_build_query($data);\n        $result = doCurl($url);\n        return json_decode($result,true);\n    }\n}"
  },
  {
    "path": "extend/Weixin.php",
    "content": "<?php\n/**\n * Created by PhpStorm.\n * User: yefy\n * Date: 2017/10/13\n * Time: 17:49\n */\n\nclass Weixin\n{\n\n\n    //构造函数，获取Access Token\n    public function __construct($appid = NULL, $appsecret = NULL)\n    {\n        if(!$appid || !$appsecret){\n            $this->appid = config('wx.app_id');\n            $this->appsecret = config('wx.app_secret');\n        }\n    }\n\n    /*\n    *  PART1 网站应用\n    */\n    //生成扫码登录的URL\n    public function qrconnect($redirect_url, $scope, $state = NULL)\n    {\n        $url = \"https://open.weixin.qq.com/connect/qrconnect?appid=\".$this->appid.\"&redirect_uri=\".urlencode($redirect_url).\"&response_type=code&scope=\".$scope.\"&state=\".$state.\"#wechat_redirect\";\n        return $url;\n    }\n\n    //生成OAuth2的Access Token\n    public function oauth2_access_token($code)\n    {\n        $url = \"https://api.weixin.qq.com/sns/oauth2/access_token?appid=\".$this->appid.\"&secret=\".$this->appsecret.\"&code=\".$code.\"&grant_type=authorization_code\";\n        $res = $this->http_request($url);\n        return json_decode($res, true);\n    }\n\n    //获取用户基本信息（OAuth2 授权的 Access Token 获取 未关注用户，Access Token为临时获取）\n    public function oauth2_get_user_info($access_token, $openid)\n    {\n        $url = \"https://api.weixin.qq.com/sns/userinfo?access_token=\".$access_token.\"&openid=\".$openid.\"&lang=zh_CN\";\n        $res = $this->http_request($url);\n        return json_decode($res, true);\n    }\n\n    public function http_request($strUrl)\n    {\n        $tmpHeader[] = \"API-RemoteIP: \" . $_SERVER['REMOTE_ADDR'];\n        $ch = curl_init();\n        curl_setopt($ch, CURLOPT_HTTPHEADER, $tmpHeader );\n        curl_setopt($ch, CURLOPT_URL, $strUrl);\n        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);\n        curl_setopt($ch, CURLOPT_TIMEOUT, 5);\n        curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );\n        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);\n        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);\n        $tmpRe = curl_exec($ch);\n        curl_close ($ch);\n        return $tmpRe;\n    }\n}"
  },
  {
    "path": "ofo 无微信支付/README.md",
    "content": "## 运行截图\n<img src=\"http://oht7mjuah.bkt.clouddn.com/%E9%A6%96%E9%A1%B5.png\" width=\"270\" height=\"480\"/>\n<img src=\"http://oht7mjuah.bkt.clouddn.com/timer-over.png\" width=\"270\" height=\"480\" />\n<img src=\"http://oht7mjuah.bkt.clouddn.com/timer.png\" width=\"270\" height=\"480\" />\n<img src=\"http://oht7mjuah.bkt.clouddn.com/wallet.png\" width=\"270\" height=\"480\" />\n<img src=\"http://oht7mjuah.bkt.clouddn.com/charge.png\" width=\"270\" height=\"480\" />\n<img src=\"http://oht7mjuah.bkt.clouddn.com/me.png\" width=\"270\" height=\"480\" />\n<img src=\"http://oht7mjuah.bkt.clouddn.com/password.png\" width=\"270\" height=\"480\"/>\n<img src=\"http://oht7mjuah.bkt.clouddn.com/warn-fill.png\" width=\"270\" height=\"480\"/>\n<img src=\"http://oht7mjuah.bkt.clouddn.com/mark.png\" width=\"270\" height=\"480\"/>\n\n## 本地运行\n~~~\ngit clone https://github.com/MiceLiD/ofo-applet.git\n~~~\n\n微信开发者工具选择目录为ofo\n\n## 非法域名报错\n微信开发者工具中请关闭校验域名，或把www.easy-mock.com添加到域名配置中\n\n## 提示\n调试看效果请用真机，开发者工具定位有bug\n\n[本小程序教程链接](http://www.jianshu.com/p/68e3b8927a77)"
  },
  {
    "path": "ofo 无微信支付/app.js",
    "content": "//app.js\nconst AV = require('/utils/av-weapp-min.js'); \nAV.init({\n  appId: 'pTf5kDMERjsFopcOt9mO4C3e-gzGzoHsz',\n  appKey: 'YRb4tW0mekPrVHpCHzokI3Bf'\n})\nApp({\n  \n})"
  },
  {
    "path": "ofo 无微信支付/app.json",
    "content": "{\n  \"pages\": [\n    \"pages/index/index\",\n    \"pages/warn/index\",\n    \"pages/scanresult/index\",\n    \"pages/billing/index\",\n    \"pages/my/index\",\n    \"pages/wallet/index\",\n    \"pages/charge/index\",\n    \"pages/logs/logs\",\n    \"pages/unlock/index\",\n    \"pages/input/index\",\n    \"pages/pay/index\"\n  ],\n  \"window\": {\n    \"backgroundTextStyle\": \"light\",\n    \"navigationBarBackgroundColor\": \"#b9dd08\",\n    \"navigationBarTitleText\": \"ofo 共享单车\",\n    \"navigationBarTextStyle\": \"black\"\n  },\n  \"tabBar\": {\n    \"list\": [\n      {\n        \"pagePath\": \"pages/index/index\",\n        \"iconPath\": \"images/bike.png\",\n        \"selectedIconPath\": \"images/bike.png\",\n        \"text\": \"用车\"\n      },\n      {\n        \"pagePath\": \"pages/my/index\",\n        \"iconPath\": \"images/my.png\",\n        \"selectedIconPath\": \"images/my.png\",\n        \"text\": \"我的\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "ofo 无微信支付/app.wxss",
    "content": "/**app.wxss**/\n.container{\n\tbackground-color: #f2f2f2;\n\theight: 100vh;\n}\n.title{\n\tbackground-color: #f2f2f2;\n\tpadding: 30rpx 0 30rpx 50rpx;\n\tfont-size: 28rpx;\n\tcolor: #000;\n}\n.tapbar{\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tbackground-color: #fff;\n\tpadding: 40rpx;\n}\n.btn-charge{\n\twidth: 90%;\n\tbackground-color: #b9dd08;\n\tmargin: 40rpx auto 30rpx;\n\ttext-align: center;\n}"
  },
  {
    "path": "ofo 无微信支付/pages/billing/index.js",
    "content": "// pages/billing/index.js\nPage({\n  data:{\n    hours: 0,\n    minuters: 0,\n    seconds: 0,\n    billing: \"正在计费\"\n  },\n// 页面加载\n  onLoad:function(options){\n    console.log(options.number);\n    //改变单车的状态\n    wx.request({\n      url: 'https://72988837.qcloud.la//index.php/api/v1/bike/status',\n      method:'post',\n      data:{\n        id:options.number\n      }\n    })\n    wx.setStorageSync('time', true);\n    // 获取车牌号，设置定时器\n    this.setData({\n      number: options.number,\n      timer: this.timer\n    })\n    // 初始化计时器\n    let s = 0;\n    let m = 0;\n    let h = 0;\n\n    //获取开始的时间\n    \n    var tmp = Date.parse(new Date()).toString();\n    tmp = tmp.substr(0, 10);\n    wx.setStorageSync('start_time', tmp);\n    // 计时开始\n    this.timer = setInterval(() => {\n      this.setData({\n        seconds: s++\n      })\n      if(s == 60){\n        s = 0;\n        m++;\n        setTimeout(() => {         \n          this.setData({\n            minuters: m\n          });\n        },1000)      \n        if(m == 60){\n          m = 0;\n          h++\n          setTimeout(() => {         \n            this.setData({\n              hours: h\n            });\n          },1000)\n        }\n      };\n    },1000)  \n  },\n// 结束骑行，清除定时器\n  endRide: function(){\n    //结束时间\n    var tmp = Date.parse(new Date()).toString();\n    tmp = tmp.substr(0, 10);\n    wx.setStorageSync('end_time', tmp);\n    //结束位置\n    // 2.获取并设置当前位置经纬度\n    wx.getLocation({\n      type: \"gcj02\",\n      success: (res) => {\n        console.log(res);\n        wx.setStorageSync('end_long', res.longitude);\n        wx.setStorageSync('end_lati', res.latitude);\n      }\n    });\n    var times = (this.data.minuters * 60 + this.data.hours * 3600 + this.data.seconds);\n    wx.setStorageSync('time', false)\n    clearInterval(this.timer);\n    this.timer = \"\";\n    this.setData({\n      billing: \"本次骑行耗时\",\n      disabled: true\n    });\n    setTimeout(()=>{\n      wx.navigateTo({\n        url: '../pay/index?times='+times+\"&bikeID=\"+this.data.number,\n      });\n    },2000);\n  },\n// 携带定时器内容回到地图\n  moveToIndex: function(){\n    // 如果定时器为空\n    if(this.timer == \"\"){\n      // 关闭计费页跳到地图\n      wx.switchTab({\n        url: '../index/index'\n      })\n    // 保留计费页跳到地图\n    }else{\n      wx.switchTab({\n        url: '../index/index?timer=' + this.timer\n      })\n    }\n  }\n})"
  },
  {
    "path": "ofo 无微信支付/pages/billing/index.json",
    "content": "{}"
  },
  {
    "path": "ofo 无微信支付/pages/billing/index.wxml",
    "content": "<!--pages/billing/index.wxml-->\n<view class=\"container\">\n    <view class=\"number\">\n        <text>当前单车编号: {{number}}</text>\n    </view>\n    <view class=\"time\">\n        <view class=\"time-title\">\n            <text>{{billing}}</text>\n        </view>\n        <view class=\"time-content\">\n            <text>{{hours}}:{{minuters}}:{{seconds}}</text>\n        </view>\n    </view>\n\n    <view class=\"endride\">\n        <button type=\"warn\" disabled=\"{{disabled}}\" bindtap=\"endRide\">结束骑行</button>\n        <button type=\"primary\" bindtap=\"moveToIndex\">回到地图</button>\n    </view>\n</view>\n"
  },
  {
    "path": "ofo 无微信支付/pages/billing/index.wxss",
    "content": ".container{\n\twidth: 100%;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: space-between;\n\tbackground-color: #fff;\n}\n.number,.endride{\n\tpadding: 60rpx 0;\n\tflex: 2;\n\twidth: 100%;\n\ttext-align: center;\n}\n.time{\n\ttext-align: center;\n\twidth: 100%;\n\tflex: 6;\n}\n.time .time-content{\n\tfont-size: 100rpx;\n}\n.endride button{\n\twidth: 90%;\n\tmargin-top: 40rpx;\n}\n\n"
  },
  {
    "path": "ofo 无微信支付/pages/charge/index.js",
    "content": "// pages/charge/index.js\nPage({\n  data:{\n    inputValue: 0\n  },\n// 页面加载\n  onLoad:function(options){\n    console.log(options);\n    this.setData({\n      from: options.from\n    })\n    wx.setNavigationBarTitle({\n      title: '充值'\n    })\n  },\n// 存储输入的充值金额\n  bindInput: function(res){\n    this.setData({\n      inputValue: res.detail.value\n    })  \n  },\n// 充值\n  charge: function(){\n    // 必须输入大于0的数字\n    var that = this;\n    if(parseInt(this.data.inputValue) <= 0 || isNaN(this.data.inputValue)){\n      wx.showModal({\n        title: \"警告\",\n        content: \"请输入金额\",\n        showCancel: false,\n        confirmText: \"确定\"\n      })\n    }else{\n      var token = wx.getStorageSync('token');\n        wx.request({\n          url: 'https://72988837.qcloud.la/index.php/api/v1/user/pay',\n          method: 'post',\n          data: {\n            from:this.data.from,\n            price: this.data.inputValue,\n          },\n          header: {\n            'token': token\n          },\n          success: function (rel) {\n            if(that.data.from == 'index') {\n              wx.setStorageSync('guarantee', that.data.inputValue);\n              wx.switchTab({\n                url: '../index/index',\n                success:function(res){\n                  wx.showToast({\n                    title: \"充值成功\",\n                    icon: \"success\",\n                    duration: 2000\n                  });\n                }\n              })\n            }else if(that.data.from == 'wallet') {\n              var balance = wx.getStorageSync('balance');\n              var price = parseFloat(that.data.inputValue) + parseFloat(balance);\n              wx.setStorageSync('balance', price);\n              wx.redirectTo({\n                url: '../wallet/index',\n                success: function (res) {\n                  wx.showToast({\n                    title: \"充值成功\",\n                    icon: \"success\",\n                    duration: 2000\n                  });\n                }\n              });\n            }else if(that.data.from == 'pay'){\n              var balance = wx.getStorageSync('balance');\n              var price = parseFloat(that.data.inputValue) +parseFloat(balance);\n              wx.setStorageSync('balance', price);\n              wx.showToast({\n                title: \"充值成功\",\n                icon: \"success\",\n                duration: 10000,\n                success:function(res) {\n                  wx.navigateBack({\n                    delta: 1,\n                  })\n                }\n              });\n                }\n          }\n        }); \n    }\n  },\n// 页面销毁，更新本地金额，（累加）\n  onUnload:function(){\n    wx.getStorage({\n      key: 'overage',\n      success: (res) => {\n        wx.setStorage({\n          key: 'overage',\n          data: {\n            overage: parseInt(this.data.inputValue) + parseInt(res.data.overage)\n          }\n        })\n      },\n      // 如果没有本地金额，则设置本地金额\n      fail: (res) => {\n        wx.setStorage({\n          key: 'overage',\n          data: {\n            overage: parseInt(this.data.inputValue)\n          },\n        })\n      }\n    }) \n  }\n})"
  },
  {
    "path": "ofo 无微信支付/pages/charge/index.json",
    "content": "{}"
  },
  {
    "path": "ofo 无微信支付/pages/charge/index.wxml",
    "content": "<!--pages/charge/index.wxml-->\n<view class=\"container\">\n    <view class=\"title\">请输入充值金额</view>\n    <view class=\"input-box\">\n        <input bindinput=\"bindInput\" />\n    </view>\n    <button bindtap=\"charge\" class=\"btn-charge\">充值</button>\n</view>\n"
  },
  {
    "path": "ofo 无微信支付/pages/charge/index.wxss",
    "content": "/* pages/charge/index.wxss */\n.input-box{\n\tbackground-color: #fff;\n\tmargin: 0 auto;\n\tpadding: 20rpx 0;\n\tborder-radius: 10rpx;\n\twidth: 90%;\n\n}\n.input-box input{\n\twidth: 100%;\n\theight: 100%;\n\ttext-align: center;\n}"
  },
  {
    "path": "ofo 无微信支付/pages/index/index.js",
    "content": "//index.js\n//获取应用实例\nvar app = getApp()\nPage({\n  data: {\n    scale: 18,\n    latitude: 0,\n    longitude: 0,\n    time:false\n  },\n// 页面加载\n  onLoad: function (options) {\n    var that = this;\n    // 2.获取并设置当前位置经纬度\n    wx.getLocation({\n      type: \"gcj02\",\n      success: (res) => {\n        \n        //获取用户的初始位置\n        wx.setStorageSync('start_long', res.longitude);\n        wx.setStorageSync('start_lati', res.latitude);\n        this.setData({\n          longitude: res.longitude,\n          latitude: res.latitude\n        });\n      }\n    });\n    wx.setStorageSync('time', false);\n    \n    \n    // this.setData({\n    //   markers:[\n    //     {\n    //       \"id\": 1,\n    //       \"title\": \"去这里\",\n    //       \"iconPath\": \"/images/markers.png\",\n    //       \"latitude\": 31.096575,\n    //       \"longitude\": 121.506271,\n    //       \"width\": 45,\n    //       \"height\": 50 \n    //     },\n    //     {\n    //       \"id\": 2,\n    //       \"title\": \"去这里\",\n    //       \"iconPath\": \"/images/markers.png\",\n    //       \"latitude\": 31.09761,\n    //       \"longitude\": 121.50666,\n    //       \"width\": 45,\n    //       \"height\": 50\n    //     }\n    //   ]\n    // })\n    // 4.请求服务器，显示附近的单车，用marker标记\n    wx.request({\n      url: 'https://72988837.qcloud.la//index.php/api/v1/bike',\n      data: {},\n      header:{\n        'Content-Type': 'application/json'\n      },\n      method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT\n      // header: {}, // 设置请求的 header\n      success: (res) => {\n        console.log(res);\n        let data = res.data.map((item, index, arr) => {\n          return {\n            \"id\": item.id,\n            \"title\": \"去这里\",\n            \"iconPath\": \"/images/markers.png\",\n            \"latitude\": item.latitude,\n            \"longitude\": item.longitude,\n            \"width\": 45,\n            \"height\": 50\n          }\n        })\n        console.log(data);\n        this.setData({\n          markers: data\n        });\n      //   console.log(res);\n      //   for (var i = 0; i < res.data.length; i++) {\n      //     data[i].id = res.data[i].id,\n      //       data[i].title = \"title\",\n      //       data[i].iconPath = \"/images/markers.png\",\n      //       data[i].latitude = res.data[i].latitude,\n      //       data[i].longitude = res.data[i].longitude,\n      //       data[i].width = res.data[i].width,\n      //       data[i].height = res.data[i].height\n      //   }\n      //   console.log(data);\n      //   this.setData({\n      //     markers: data\n      //   })\n        }\n    });\n    // 3.设置地图控件的位置及大小，通过设备宽高定位\n    wx.getSystemInfo({\n      success: (res) => {\n        this.setData({\n          controls: [{\n            id: 1,\n            iconPath: '/images/location.png',\n            position: {\n              left: 20,\n              top: res.windowHeight - 80,\n              width: 50,\n              height: 50\n            },\n            clickable: true\n          },\n          {\n            id: 2,\n            iconPath: '/images/use.png',\n            position: {\n              left: res.windowWidth/2 - 45,\n              top: res.windowHeight - 100,\n              width: 90,\n              height: 90\n            },\n            clickable: true\n          },\n          {\n            id: 3,\n            iconPath: '/images/warn.png',\n            position: {\n              left: res.windowWidth - 70,\n              top: res.windowHeight - 80,\n              width: 50,\n              height: 50\n            },\n            clickable: true\n          },\n          {\n            id: 4,\n            iconPath: '/images/marker.png',\n            position: {\n              left: res.windowWidth/2 - 11,\n              top: res.windowHeight/2 - 45,\n              width: 22,\n              height: 45\n            },\n            clickable: true\n          },]\n        });\n      }\n    });\n  },\n// 页面显示\n  onShow: function(){\n    // 1.创建地图上下文，移动当前位置到地图中心\n    this.mapCtx = wx.createMapContext(\"ofoMap\");\n    this.movetoPosition()\n  },\n// 地图控件点击事件\n  bindcontroltap: function(e){\n    // 判断点击的是哪个控件 e.controlId代表控件的id，在页面加载时的第3步设置的id\n    switch(e.controlId){\n      // 点击定位控件\n      case 1: this.movetoPosition();\n        break;\n      // 点击立即用车，判断当前是否正在计费\n      case 2: if(!wx.getStorageSync('time')){\n        //根据token判断是否登录，没有登录，先登录,第一种情况没有token\n        //直接跳转到登录页，第二种情况有token，但是已经过期了，需要先删除token,再重新登录\n          if(!wx.getStorageSync('token')){\n            wx.showModal({\n              title: '请先登录',\n              content: '用车失败',\n              success:function(res){\n                wx.switchTab({\n                  url: '../my/index',\n                });\n              }\n            });\n          }else if(wx.getStorageSync('token')) {\n            var token = wx.getStorageSync('token');\n            wx.request({\n              url: 'https://72988837.qcloud.la//index.php/api/v1/token/verify',\n              method:'post',\n              header:{\n                token:token\n              },\n              success:function(res){\n                if(res.statusCode == '401') {\n                  wx.removeStorageSync('userInfo');\n                  wx.showModal({\n                    title: '用车失败',\n                    content: '登录已过期，请重新登录',\n                    showCancel: false,\n                    success: function(res) {\n                      wx.switchTab({\n                        url: '../my/index',\n                      });\n                    },\n                  });\n                }else if(wx.getStorageSync('guarantee') == 0) {\n                  wx.showModal({\n                    title: '用车失败',\n                    content: '您的押金为0,请先充值199元',\n                    showCancel: false,\n                    success: function(res) {\n                      wx.navigateTo({\n                        url: '../charge/index?from=index',\n                      });\n                    },\n                  })\n                }else {\n                  wx.setStorageSync('login', true);\n                  wx.navigateTo({\n                    url: '../unlock/index',\n                  })\n                }\n              }\n            });\n          }\n        // 当前已经在计费就回退到计费页\n        }else{\n          wx.navigateTo({\n            url: '../billing/index',\n          })\n        }  \n        break;\n      // 点击保障控件，跳转到报障页\n      case 3: wx.navigateTo({\n          url: '../warn/index'\n        });\n        break; \n      default: break;\n    }\n  },\n// 地图视野改变事件\n  bindregionchange: function(e){\n    // 拖动地图，获取附件单车位置\n    if(e.type == \"begin\"){\n      wx.request({\n        url: 'https://72988837.qcloud.la//index.php/api/v1/bike',\n        header: {\n          'Content-Type': 'application/json'\n        },\n        data: {},\n        method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT\n        // header: {}, // 设置请求的 header\n        success: (res) => {\n          for (var i = 0; i < res.data.length; i++) {\n            res.data[i].title = '去这里',\n              res.data[i].iconPath = \"/images/markers.png\",\n              res.data[i].width = 45,\n              res.data[i].height = 50\n          }\n          this.setData({\n            _markers: res.data\n          })\n        }\n      })\n    // 停止拖动，显示单车位置\n    }else if(e.type == \"end\"){\n        this.setData({\n          markers: this.data._markers\n        })\n    }\n  },\n// 地图标记点击事件，连接用户位置和点击的单车位置\n  bindmarkertap: function(e){\n    console.log(e);\n    let _markers = this.data.markers;\n    let markerId = e.markerId;\n    let currMaker = _markers[markerId];\n    this.setData({\n      polyline: [{\n        points: [{\n          longitude: this.data.longitude,\n          latitude: this.data.latitude\n        }, {\n          longitude: currMaker.longitude,\n          latitude: currMaker.latitude\n        }],\n        color:\"#FF0000DD\",\n        width: 1,\n        dottedLine: true\n      }],\n      scale: 18\n    })\n  },\n// 定位函数，移动位置到地图中心\n  movetoPosition: function(){\n    this.mapCtx.moveToLocation();\n  }\n})\n"
  },
  {
    "path": "ofo 无微信支付/pages/index/index.json",
    "content": "{}"
  },
  {
    "path": "ofo 无微信支付/pages/index/index.wxml",
    "content": "<!--index.wxml-->\n<view class=\"container\">\n  <map id=\"ofoMap\" latitude=\"{{latitude}}\" longitude=\"{{longitude}}\" scale=\"{{scale}}\" bindregionchange=\"bindregionchange\" polyline=\"{{polyline}}\" markers=\"{{markers}}\" controls=\"{{controls}}\" bindmarkertap=\"bindmarkertap\"  bindcontroltap=\"bindcontroltap\" show-location/>\n</view>\n"
  },
  {
    "path": "ofo 无微信支付/pages/index/index.wxss",
    "content": "/**index.wxss**/\n.container{\n  position: relative;\n  width: 100%;\n  height: 100vh;\n}\n#ofoMap{\n  position: absolute;\n  left: 0;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  width: 100%;\n  height: 100%;\n  z-index: 1;\n}"
  },
  {
    "path": "ofo 无微信支付/pages/input/index.js",
    "content": "// index.js\nPage({\n\n  /**\n   * 页面的初始数据\n   */\n  data: {\n\n  },\n\n  /**\n   * 生命周期函数--监听页面加载\n   */\n  onLoad: function (options) {\n  \n  },\n\n  numberChange:function(e) {\n    this.data.bikeID = e.detail.value;\n  },\n\n  userBike:function(){\n    console.log(this.data.bikeID);\n    if (this.data.bikeID == undefined || isNaN(this.data.bikeID)) {\n      wx.showModal({\n        title: '开锁失败',\n        content: '请输入正确的车牌号',\n        showCancel: false,\n      });\n    }else {\n      // 正在获取密码通知\n      wx.showLoading({\n        title: '正在获取密码',\n        mask: true\n      }),\n        wx.request({\n          url: 'https://72988837.qcloud.la//index.php/api/v1/bike',\n          data: { id: this.data.bikeID },\n          method: 'POST',\n          success: function (res) {\n            // 请求成功隐藏等待框\n            wx.hideLoading();\n            if (res.statusCode == '401') {\n              wx.showModal({\n                title: '开锁失败',\n                content: res.data.msg,\n                showCancel: false,\n                confirmText: '确定',\n              })\n            } else {\n              //携带密码和车号跳转到密码页\n              console.log(res);\n              wx.redirectTo({\n                url: '../scanresult/index?password=' + res.data.password + '&number=' + res.data.id,\n                success: function (res) {\n                  wx.showToast({\n                    title: '获取密码成功',\n                    duration: 1000\n                  });\n                }\n              });\n            }\n          }\n        });\n    }\n    \n  },\n})"
  },
  {
    "path": "ofo 无微信支付/pages/input/index.json",
    "content": "{}"
  },
  {
    "path": "ofo 无微信支付/pages/input/index.wxml",
    "content": "<view>\n      <view class=\"input-top\">计费说明:1元/小时</view>\n      <view class=\"input-tips\">温馨提示:若输错车牌号,将无法打开车锁</view>\n      <input class=\"input-num\" bindinput=\"numberChange\" name=\"number\" focus=\"true\" placeholder=\"请输入车牌号\" type=\"number\" />\n      <view class=\"input-bottom\" bindtap=\"userBike\">立即用车</view>\n  </view>\n"
  },
  {
    "path": "ofo 无微信支付/pages/input/index.wxss",
    "content": "/* index.wxss */\n.input-top{\n  text-align: center;\n  margin: 40rpx auto;\n  border-radius: 20rpx;\n  background-color: #9c9a9a;\n  font-size: 30rpx;\n  width: 40%;\n}\n\n.input-tips{\n  text-align: center;\n  font-size: 20rpx;\n  color: red;\n}\n.input-num {\n  text-align: center;\n  margin: 20rpx auto; \n  height: 80rpx;\n  width: 80%;\n  border-radius: 40rpx;\n  border:1rpx solid #f5f804;\n}\n\n.input-bottom {\n  text-align: center;\n  height: 80rpx;\n  margin: 30rpx auto;\n  width: 80%;\n  line-height: 80rpx;\n  border-radius: 40rpx;\n  background-color:#f5f804; \n}"
  },
  {
    "path": "ofo 无微信支付/pages/logs/logs.js",
    "content": "//logs.js\nvar util = require('../../utils/util.js')\nPage({\n  data: {\n    logs: []\n  },\n  onLoad: function () {\n    this.setData({\n      logs: (wx.getStorageSync('logs') || []).map(function (log) {\n        return util.formatTime(new Date(log))\n      })\n    })\n  }\n})\n"
  },
  {
    "path": "ofo 无微信支付/pages/logs/logs.json",
    "content": "{\n    \"navigationBarTitleText\": \"查看启动日志\"\n}"
  },
  {
    "path": "ofo 无微信支付/pages/logs/logs.wxml",
    "content": "<!--logs.wxml-->\n<view class=\"container log-list\">\n  <block wx:for=\"{{logs}}\" wx:for-item=\"log\" wx:key=\"*this\">\n    <text class=\"log-item\">{{index + 1}}. {{log}}</text>\n  </block>\n</view>\n"
  },
  {
    "path": "ofo 无微信支付/pages/logs/logs.wxss",
    "content": ".log-list {\n  display: flex;\n  flex-direction: column;\n  padding: 40rpx;\n}\n.log-item {\n  margin: 10rpx;\n}\n"
  },
  {
    "path": "ofo 无微信支付/pages/my/index.js",
    "content": "// pages/my/index.js\nPage({\n  data:{\n    // 用户信息\n    from:'personal',\n    userInfo: {\n      avatarUrl: \"\",\n      nickName: \"未登录\"\n    },\n    bType: \"primary\", // 按钮类型\n    actionText: \"登录\", // 按钮文字提示\n    lock: false //登录按钮状态，false表示未登录\n  },\n// 页面加载\n  onLoad:function(){\n    // 设置本页导航标题\n    wx.setNavigationBarTitle({\n      title: '个人中心'\n    })\n    // 获取本地数据-用户信息\n    wx.getStorage({\n      key: 'userInfo',\n      // 能获取到则显示用户信息，并保持登录状态，不能就什么也不做\n      success: (res) => {\n        wx.hideLoading();\n        this.setData({\n          userInfo: {\n            avatarUrl: res.data.userInfo.avatarUrl,\n            nickName: res.data.userInfo.nickName\n          },\n          bType: 'warn',\n          actionText: '退出登录',\n          lock: true\n        })\n      }\n    });\n  },\n\n//生命周期函数--监听页面显示\n  onShow: function () {\n    var that = this;\n    if (!wx.getStorageSync('token')) {\n      this.data.lock = false;\n      this.setData({\n        userInfo: {\n          avatarUrl: \"\",\n          nickName: \"未登录\"\n        },\n        bType: \"primary\",\n        actionText: \"登录\"\n      })\n    }\n  if(wx.getStorageSync('token')) {\n    var token = wx.getStorageSync('token');\n    wx.request({\n      url: 'https://72988837.qcloud.la//index.php/api/v1/token/verify',\n      method: 'post',\n      header: {\n        token: token\n      },\n      success: function (res) {\n        if (res.statusCode == '401') {\n          that.setData({\n            userInfo: {\n              avatarUrl: \"\",\n              nickName: \"未登录\"\n            },\n            bType: \"primary\",\n            actionText: \"登录\"\n          });\n          // wx.showModal({\n          //   title: '用车失败',\n          //   content: '登录已过期，请重新登录',\n          //   showCancel: false,\n          // });\n        }\n      }\n    });\n    }\n  },\n\n\n// 登录或退出登录按钮点击事件\n  bindAction: function(){\n    // 如果没有登录，登录按钮操作\n    this.data.lock = !this.data.lock;\n    if(this.data.lock){\n      wx.showLoading({\n        title: \"正在登录\"\n      });\n      var that = this;\n      wx.login({\n        success: (res) => {\n          console.log(res);\n          wx.request({\n            url: 'https://72988837.qcloud.la//index.php/api/v1/token/user',\n            header: {\n              'Content-Type': 'application/json'\n            },\n            method:'post',\n            data:{code:res.code},\n            success:function(rel) {\n              wx.setStorageSync('login',true);\n              console.log(rel.data.token);\n              wx.setStorageSync('token', rel.data.token);\n              //把余额和保证金存储到缓存中\n              var that = this;\n              var token = wx.getStorageSync('token');\n              wx.request({\n                url: 'https://72988837.qcloud.la//index.php/api/v1/user/wallet',\n                method: 'post',\n                header: {\n                  'token': token\n                },\n                success: function (res) {\n                  wx.setStorageSync('balance', res.data.balance);\n                  wx.setStorageSync('guarantee', res.data.guarantee);\n                }\n              });\n            }\n          });\n          wx.hideLoading();\n          wx.getUserInfo({\n            withCredentials: false,\n            success: (res) => {\n              this.setData({\n                userInfo: {\n                  avatarUrl: res.userInfo.avatarUrl,\n                  nickName: res.userInfo.nickName\n                },\n                bType: \"warn\",\n                actionText: \"退出登录\"\n              });\n              wx.setStorageSync('userInfo', res);\n            }     \n          })\n        }\n      })\n    // 如果已经登录，退出登录按钮操作     \n    }else{\n      wx.showModal({\n        title: \"确认退出?\",\n        content: \"退出后将不能使用ofo\",\n        success: (res) => {\n          if(res.confirm){\n            console.log(\"确定\")\n            // 退出登录则移除本地用户信息\n            wx.removeStorageSync('userInfo');\n            wx.removeStorageSync('token');\n            this.setData({\n              userInfo: {\n                avatarUrl: \"\",\n                nickName: \"未登录\"\n              },\n              bType: \"primary\",\n              actionText: \"登录\"\n            })\n          }else {\n            console.log(\"cancel\")\n            this.setData({\n              lock: true\n            })\n          }\n        }\n      })\n    }   \n  },\n// 跳转至钱包\n  movetoWallet: function(){\n    // var that = this;\n    // var token = wx.getStorageSync('token');\n    // wx.request({\n    //   url: 'https://72988837.qcloud.la//index.php/api/v1/user/wallet',\n    //   method: 'post',\n    //   header: {\n    //     'token': token\n    //   },\n    //   success: function (res) {\n    //     if (res.data.guarantee == 0){\n    //       wx.showModal({\n    //         title: '请先充值',\n    //         content: '您的押金为0，请先充值199元',\n    //         success: function(res) {\n    //           wx.redirectTo({\n    //             url: '../charge/index'+\"?from=\"+that.data.from,\n    //           })\n    //         },\n    //         fail: function(res) {},\n    //         complete: function(res) {},\n    //       })\n    //     }else {\n          wx.navigateTo({\n            url: '../wallet/index',\n          });\n        }\n  //     }\n  //   });\n  // },\n\n  \n    \n})"
  },
  {
    "path": "ofo 无微信支付/pages/my/index.json",
    "content": "{}"
  },
  {
    "path": "ofo 无微信支付/pages/my/index.wxml",
    "content": "<!--pages/my/index.wxml-->\n<view class=\"container\">\n    <view class=\"user-info\">\n    <block wx:if=\"{{userInfo.avatarUrl != ''}}\">\n        <image src=\"{{userInfo.avatarUrl}}\"></image>\n    </block>\n        <text>{{userInfo.nickName}}</text>\n    </view>\n    <block wx:if=\"{{userInfo.avatarUrl != ''}}\">\n    <view class=\"my-wallet tapbar\" bindtap=\"movetoWallet\">\n        <text>我的钱包</text>\n        <text>></text>\n    </view>\n    </block>\n    <button bindtap=\"bindAction\" class=\"btn-login\" hover-class=\"gray\" type=\"{{bType}}\" >{{actionText}}</button>\n</view>\n"
  },
  {
    "path": "ofo 无微信支付/pages/my/index.wxss",
    "content": "/* pages/my/index.wxss */\n.user-info{\n\tbackground-color: #fff;\n\tpadding-top: 60rpx;\n}\n.user-info image{\n\tdisplay: block;\n\twidth: 180rpx;\n\theight: 180rpx;\n\tborder-radius: 50%;\n\tmargin: 0 auto 40rpx;\n\tbox-shadow: 0 0 20rpx rgba(0,0,0,.2)\n}\n.user-info text{\n\tdisplay: block;\n\ttext-align: center;\n\tpadding: 30rpx 0;\n\tmargin-bottom: 30rpx;\n}\n.btn-login{\n\tposition: absolute;\n\tbottom: 60rpx;\n\twidth: 90%;\n\tleft: 50%;\n\tmargin-left: -45%;\n}\n.gray{\n\tbackground-color: #ccc;\n}"
  },
  {
    "path": "ofo 无微信支付/pages/pay/index.js",
    "content": "// index.js\nPage({\n\n  /**\n   * 页面的初始数据\n   */\n  data: {\n  \n  },\n\n  /**\n   * 生命周期函数--监听页面加载\n   */\n  onLoad: function (options) {\n    var times = options.times;\n    var price = Math.ceil(times/3600);\n    var bikeID = options.bikeID;\n    this.setData({\n      price:price,\n      bikeID:bikeID\n    });\n  },\n\n  pay:function(){\n    var that = this;\n    if ((wx.getStorageSync('balance')-this.data.price)>=0){\n      wx.request({\n        url: 'https://72988837.qcloud.la//index.php/api/v1/user/record',\n        method: 'post',\n        header: {\n          token: wx.getStorageSync('token')\n        },\n        data: {\n          'start_time': wx.getStorageSync('start_time'),\n          'end_time': wx.getStorageSync('end_time'),\n          'start_long': wx.getStorageSync('start_long'),\n          'start_lati': wx.getStorageSync('start_lati'),\n          'end_long': wx.getStorageSync('end_long'),\n          'end_lati': wx.getStorageSync('end_lati'),\n          'price': this.data.price,\n          'bikeID': this.data.bikeID\n        },\n        success: function (res) {\n          //更新余额的缓存\n          var balance = wx.getStorageSync('balance');\n          var price =balance - that.data.price;\n          wx.setStorageSync('balance', price);\n          //清除时间和位置的缓存\n          wx.removeStorageSync('end_time');\n          wx.removeStorageSync('start_time');\n          wx.removeStorageSync('start_long');\n          wx.removeStorageSync('start_lati');\n          wx.removeStorageSync('end_long');\n          wx.removeStorageSync('end_lati');\n          wx.showToast({\n            title: '支付成功',\n            icon: 'success',\n            duration: 6000,\n            success: function(res) {\n              wx.switchTab({\n                url: '../index/index',\n              })\n            },\n\n          })\n        }\n      });\n    }else {\n      wx.showModal({\n        title: '支付失败',\n        content: '您的余额不足，请先充值',\n        success: function(res) {\n          wx.navigateTo({\n            url: '../charge/index?from=pay',\n          })\n        },\n        \n      })\n    }\n    \n  },\n\n  /**\n   * 生命周期函数--监听页面初次渲染完成\n   */\n  onReady: function () {\n  \n  },\n\n  /**\n   * 生命周期函数--监听页面显示\n   */\n  onShow: function () {\n  \n  },\n\n  /**\n   * 生命周期函数--监听页面隐藏\n   */\n  onHide: function () {\n  \n  },\n\n  /**\n   * 生命周期函数--监听页面卸载\n   */\n  onUnload: function () {\n  \n  },\n\n  /**\n   * 页面相关事件处理函数--监听用户下拉动作\n   */\n  onPullDownRefresh: function () {\n  \n  },\n\n  /**\n   * 页面上拉触底事件的处理函数\n   */\n  onReachBottom: function () {\n  \n  },\n\n  /**\n   * 用户点击右上角分享\n   */\n  onShareAppMessage: function () {\n  \n  }\n})"
  },
  {
    "path": "ofo 无微信支付/pages/pay/index.json",
    "content": "{}"
  },
  {
    "path": "ofo 无微信支付/pages/pay/index.wxml",
    "content": "<view class=\"\">\n  <view class=\"top\">关锁后请打乱密码,注意检查车篮,带好随身物品</view>\n  <view class=\"distance\">本次行程需要支付(元)</view>\n  <view class=\"price\">{{price}}.00</view>\n  <view class=\"middle\">\n    <view class=\"total-fee\">总费用:{{price}}元</view>\n    <view class=\"discount\">未使用优惠券></view>\n  </view>\n  <view class=\"pay\" bindtap=\"pay\">确认支付</view>\n  \n</view>\n"
  },
  {
    "path": "ofo 无微信支付/pages/pay/index.wxss",
    "content": ".top {\n  font-size: 30rpx;\n  height: 70rpx;\n  width: 100%;\n  color: #d43e5d;\n  text-align: center;\n  line-height: 70rpx;\n  background-color: #d7e482;\n}\n\n.distance {\n  text-align: center;\n  margin-top:80rpx;\n  height: 10rpx;\n  font-size: 30rpx;\n  color: #b3b3b1;\n}\n\n.price {\n  margin-top: 30rpx;\n  text-align: center;\n  font-size: 80rpx;\n  font-weight: bold;\n}\n\n.middle {\n  display: flex;\n  justify-content: space-between;\n  align-content: center;\n  margin-top: 50rpx;\n  margin-bottom: 80rpx;\n  padding: 0 100rpx 0 100rpx;\n}\n\n.total-fee {\n  color: #b3b3b1;\n  font-size: 30rpx;\n}\n\n.discount {\n  color:#d43e5d;\n  font-size: 30rpx; \n}\n\n.pay {\n  text-align: center;\n  height: 80rpx;\n  line-height: 80rpx;\n  width: 80%;\n  margin: 0 auto;\n  border-radius: 40rpx;\n  background-color: #f5f804;\n  box-shadow: 0 10rpx 0 #d4d630;\n}"
  },
  {
    "path": "ofo 无微信支付/pages/scanresult/index.js",
    "content": "// pages/scanresult/index.js\nPage({\n  data:{\n    time: 3\n  },\n// 页面加载\n  onLoad:function(options){\n    // 获取解锁密码\n    this.setData({\n      password: options.password\n    })\n    // 设置初始计时秒数\n    let time = 3;\n    // 开始定时器\n    this.timer = setInterval(() => {\n      this.setData({\n        time: -- time\n      });\n      // 读完秒后携带单车号码跳转到计费页\n      if(time < 0){\n        clearInterval(this.timer)\n        wx.redirectTo({\n          url: '../billing/index?number=' + options.number\n        })\n      }\n    },1000)\n  },\n// 点击去首页报障\n  moveToWarn: function(){\n    clearInterval(this.timer)\n    wx.redirectTo({\n      url: '../warn/index'\n    })\n  }\n})"
  },
  {
    "path": "ofo 无微信支付/pages/scanresult/index.json",
    "content": "{}"
  },
  {
    "path": "ofo 无微信支付/pages/scanresult/index.wxml",
    "content": "<!--pages/scanresult/index.wxml-->\n<view class=\"container\">\n    <view class=\"password-title\">\n        <text>开锁密码</text>\n    </view>\n    <view class=\"password-content\">\n        <text>{{password}}</text>\n    </view>\n    <view class=\"tips\">\n        <text>请使用密码解锁，{{time}}s后开始计费</text>\n        <view class=\"tips-action\" bindtap=\"moveToWarn\">\n            车辆有问题?\n            <text class=\"tips-href\">回首页去车辆报障</text>\n        </view>\n    </view>\n</view>"
  },
  {
    "path": "ofo 无微信支付/pages/scanresult/index.wxss",
    "content": ".container{\n\twidth: 100%;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: space-between;\n\tbackground-color: #fff;\n}\n.password-title,.tips{\n\twidth: 100%;\n\tflex: 1;\n\ttext-align: center;\n\tpadding: 60rpx 0;\n}\n.password-content{\n\twidth: 100%;\n\tflex: 8;\n\ttext-align: center;\n\tfont-size: 240rpx;\n\tfont-weight: 900;\n}\n.tips{\n\tfont-size: 32rpx;\n}\n.tips .tips-action{\n\tmargin-top: 20rpx;\t\n}\n.tips .tips-href{\n\tcolor: #b9dd08\n}\n"
  },
  {
    "path": "ofo 无微信支付/pages/unlock/index.js",
    "content": "// index.js\nPage({\n\n  /**\n   * 页面的初始数据\n   */\n  data: {\n    type:'scan'\n  },\n\n  /**\n   * 生命周期函数--监听页面加载\n   */\n  onLoad: function (options) {\n  },\n\n  /**\n   * 生命周期函数--监听页面初次渲染完成\n   */\n  onReady: function () {\n  \n  },\n  scan:function() {\n      wx.scanCode({\n        success: (res) => {\n          // 正在获取密码通知\n          wx.showLoading({\n            title: '正在获取密码',\n            mask: true\n          })\n          // 请求服务器获取密码和车号\n          wx.request({\n            url: 'https://www.easy-mock.com/mock/59098d007a878d73716e966f/ofodata/password',\n            data: {},\n            method: 'GET', \n            success: function(res){\n              // 请求密码成功隐藏等待框\n              wx.hideLoading();\n              // 携带密码和车号跳转到密码页\n              wx.redirectTo({\n                url: '../scanresult/index?password=' + res.data.data.password + '&number=' + res.data.data.number,\n                success: function(res){\n                  wx.showToast({\n                    title: '获取密码成功',\n                    duration: 1000\n                  })\n                }\n              })           \n            }\n          })\n        }\n      })\n  },\n\n  changeType:function() {\n    wx.redirectTo({\n      url: '../input/index',\n    })\n    \n  },\n\n  /**\n   * 生命周期函数--监听页面显示\n   */\n  onShow: function () {\n  \n  },\n\n  /**\n   * 生命周期函数--监听页面隐藏\n   */\n  onHide: function () {\n  \n  },\n\n  /**\n   * 生命周期函数--监听页面卸载\n   */\n  onUnload: function () {\n  \n  },\n\n  /**\n   * 页面相关事件处理函数--监听用户下拉动作\n   */\n  onPullDownRefresh: function () {\n  \n  },\n\n  /**\n   * 页面上拉触底事件的处理函数\n   */\n  onReachBottom: function () {\n  \n  },\n\n  /**\n   * 用户点击右上角分享\n   */\n  onShareAppMessage: function () {\n  \n  }\n})"
  },
  {
    "path": "ofo 无微信支付/pages/unlock/index.json",
    "content": "{}"
  },
  {
    "path": "ofo 无微信支付/pages/unlock/index.wxml",
    "content": "<view class=\"\">\n  <view class=\"text-box\">\n    \n      <view class=\"top\">您是有押金用户,可以正常用车</view>\n      <view class=\"middle\">请规范用车,用完记得结束行程</view>\n      <view class=\"scan\" bindtap=\"scan\" >扫码骑车</view>\n      <view class=\"bottom\" bindtap=\"changeType\">手动输入</view>\n    \n  </view>\n</view>\n"
  },
  {
    "path": "ofo 无微信支付/pages/unlock/index.wxss",
    "content": "/* index.wxss */\n\n.top {\n  font-size: 28rpx;\n  text-align: center;\n  line-height: 30rpx;\n  margin: 30px;\n  color: #169e99;\n}\n\n.middle {\n  font-size: 28rpx;\n  text-align: center;\n  line-height: 30rpx;\n  margin: 20px 20px 40px;\n}\n\n.scan {\n  text-align: center;\n  height: 80rpx;\n  margin: 0 auto;\n  width: 80%;\n  line-height: 80rpx;\n  border-radius: 40rpx;\n  background-color: #f5f804;\n}\n\n.bottom {\n  text-align: center;\n  height: 80rpx;\n  margin: 30rpx auto;\n  width: 80%;\n  line-height: 80rpx;\n  border-radius: 40rpx;\n  border:1rpx solid #93938d;\n}\n\n"
  },
  {
    "path": "ofo 无微信支付/pages/wallet/index.js",
    "content": "// pages/wallet/index.js\nPage({\n  data:{\n    from: 'wallet',\n    overage: 0,\n    ticket: 0\n  },\n// 页面加载\n  onLoad:function(options){\n     wx.setNavigationBarTitle({\n       title: '我的钱包'\n     });\n     this._loadData();\n  },\n\n  _loadData() {\n    var that = this;\n    var token = wx.getStorageSync('token');\n    wx.request({\n      url: 'https://72988837.qcloud.la/index.php/api/v1/user/wallet',\n      method:'post',\n      header:{\n        'token':token\n      },\n      success:function(res){\n        console.log(res);\n        that.setData({\n          userInfo:res.data,\n        });\n      }\n    });\n  },\n// 页面加载完成，更新本地存储的overage\n  onReady:function(){\n     wx.getStorage({\n      key: 'overage',\n      success: (res) => {\n        this.setData({\n          overage: res.data.overage\n        })\n      }\n    })\n  },\n// 页面显示完成，获取本地存储的overage\n  onShow:function(){\n    wx.getStorage({\n      key: 'overage',\n      success: (res) => {\n        this.setData({\n          overage: res.data.overage\n        })\n      }\n    }) \n  },\n// 余额说明\n  overageDesc: function(){\n    wx.showModal({\n      title: \"\",\n      content: \"充值余额0.00元+活动赠送余额0.00元\",\n      showCancel: false,\n      confirmText: \"我知道了\",\n    })\n  },\n// 跳转到充值页面\n  movetoCharge: function(){\n    // 关闭当前页面，跳转到指定页面，返回时将不会回到当前页面\n    wx.redirectTo({\n      url: '../charge/index'+\"?from=\"+this.data.from\n    })\n  },\n// 用车券\n  showTicket: function(){\n    wx.showModal({\n      title: \"\",\n      content: \"你没有用车券了\",\n      showCancel: false,\n      confirmText: \"好吧\",\n    })\n  },\n// 押金退还\n  showDeposit: function(){\n    wx.showModal({\n      title: \"\",\n      content: \"押金会立即退回，退款后，您将不能使用ofo共享单车确认要进行此退款吗？\",\n      cancelText: \"继续使用\",\n      cancelColor: \"#b9dd08\",\n      confirmText: \"押金退款\",\n      confirmColor: \"#ccc\",\n      success: (res) => {\n        if(res.confirm){\n          wx.request({\n            url: 'https://72988837.qcloud.la/index.php/api/v1/user/refund',\n            header:{\n              token:wx.getStorageSync('token')\n            },\n            method:'post',\n            success:function(res) {\n            wx.setStorageSync('guarantee', 0.00);\n             wx.showModal({\n               title: '操作成功',\n               content: '押金已经退还到您的钱包中，注意查收',\n               showCancel:true,\n               success:function(res){\n                 wx.switchTab({\n                   url: '../index/index',\n                 })\n               }\n             })\n            }\n          });\n        }\n      }\n    });\n  },\n// 关于ofo\n  showInvcode: function(){\n    wx.showModal({\n      title: \"ofo共享单车\",\n      content: \"微信服务号：ofobike,网址：m.ofo.so\",\n      showCancel: false,\n      confirmText: \"玩的6\"\n    })\n  }\n})"
  },
  {
    "path": "ofo 无微信支付/pages/wallet/index.json",
    "content": "{}"
  },
  {
    "path": "ofo 无微信支付/pages/wallet/index.wxml",
    "content": "<!--pages/wallet/index.wxml-->\n<view class=\"container\">\n    <view class=\"overage\">\n        <view>\n            <text class=\"overage-header\">我的余额（元）</text>\n        </view>\n        <view>\n            <text class=\"overage-amount\">{{userInfo.balance}}</text>\n        </view>\n        <view>\n            <text bindtap=\"overageDesc\" class=\"overage-desc\">余额说明</text>\n        </view>       \n    </view>\n    <button bindtap=\"movetoCharge\" class=\"btn-charge\">充值</button>\n    <view bindtap=\"showTicket\" class=\"my-ticket tapbar\">\n        <text>我的用车券</text>\n        <text><text class=\"c-g\">{{ticket}}张</text>></text>\n    </view>\n    <view bindtap=\"showDeposit\" class=\"my-deposit tapbar\">\n        <text>我的押金</text>\n        <text><text class=\"c-y\">{{userInfo.guarantee}}元，押金退款</text>></text>\n    </view>\n    <view bindtap=\"showInvcode\" class=\"my-invcode tapbar\">\n        <text>关于ofo</text>\n        <text>></text>\n    </view>\n</view>\n"
  },
  {
    "path": "ofo 无微信支付/pages/wallet/index.wxss",
    "content": "/* pages/wallet/index.wxss */\n.overage{\n\tbackground-color: #fff;\n\tpadding: 40rpx 0;\n\ttext-align: center;\n}\n.overage-header{\n\tfont-size: 24rpx;\n}\n.overage-amount{\n\tdisplay: inline-block;\n\tpadding: 20rpx 0;\n\tfont-size: 100rpx;\n\tfont-weight: 700;\n}\n.overage-desc{\n\tpadding: 10rpx 30rpx;\n\tfont-size: 24rpx;\n\tborder-radius: 40rpx;\n\tborder: 1px solid #666;\n}\n.my-deposit{\n\tmargin-top: 2rpx;\n}\n.my-invcode{\n\tmargin-top: 40rpx;\n}\n.c-y{\n\tcolor: #b9dd08;\n\tpadding-top: -5rpx;\n\tpadding-right: 10rpx;\n}\n.c-g{\n\tpadding-top: -5rpx;\n\tpadding-right: 10rpx;\n}\n"
  },
  {
    "path": "ofo 无微信支付/pages/warn/index.js",
    "content": "// pages/wallet/index.js\nconst AV = require('../../utils/av-weapp-min.js'); \nPage({\n  data:{\n    // 故障车周围环境图路径数组\n    picUrls: [],\n    // 故障车编号和备注\n    inputValue: {\n      num: 0,\n      desc: \"\"\n    },\n    // 故障类型数组\n    checkboxValue: [],\n    // 选取图片提示\n    actionText: \"拍照/相册\",\n    // 提交按钮的背景色，未勾选类型时无颜色\n    btnBgc: \"\",\n    // 复选框的value，此处预定义，然后循环渲染到页面\n  },\n// 页面加载\n  onLoad:function(options){\n    var that = this;\n    wx.setNavigationBarTitle({\n      title: '报障维修'\n    });\n    \n    //获取故障的类型\n    wx.request({\n      url: 'https://72988837.qcloud.la//index.php/api/v1/trouble',\n      method:'post',\n      success:function(res) {\n        let data = res.data.map((item, index, arr) => {\n          return {\n            \"id\": item.id,\n            \"value\": item.name\n          }\n        })\n        console.log(data);\n        that.setData({\n          itemsValue: data\n        });\n      }\n    })\n  },\n// 勾选故障类型，获取类型值存入checkboxValue\n  checkboxChange: function(e){\n    let _values = e.detail.value;\n    if(_values.length == 0){\n      this.setData({\n        btnBgc: \"\"\n      })\n    }else{\n      this.setData({\n        checkboxValue: _values,\n        btnBgc: \"#b9dd08\"\n      })\n    }   \n  },\n// 输入单车编号，存入inputValue\n  numberChange: function(e){\n    this.setData({\n      inputValue: {\n        num: e.detail.value,\n        desc: this.data.inputValue.desc\n      }\n    })\n  },\n// 输入备注，存入inputValue\n  descChange: function(e){\n    this.setData({\n      inputValue: {\n        num: this.data.inputValue.num,\n        desc: e.detail.value\n      }\n    })\n  },\n// 提交到服务器\n  formSubmit: function(e){\n    //获取单车的位置\n    this.setData({\n      address: {\n        'start_lati': wx.getStorageSync('start_lati'),\n        'start_long': wx.getStorageSync('start_long')\n      \n    }});\n    //设置需要提交的数据\n    this.setData({\n      record:{\n        picUrls: this.data.picUrls,\n        inputValue: this.data.inputValue,\n        checkboxValue: this.data.checkboxValue,\n        address:this.data.address\n      }\n    });\n\n    console.log(this.data.record);\n    if(this.data.checkboxValue.length> 0){\n      wx.request({\n        url: 'https://72988837.qcloud.la//index.php/api/v1/trouble/record',\n        data: {\n          record:this.data.record\n        },\n        method: 'post', // POST\n        header:{\n          'content-type':'application/json',\n          'token':wx.getStorageSync('token')\n        },\n        success: function(res){\n          console.log(res);\n          if(res.statusCode == '401') {\n            wx.showModal({\n              title: '提交失败',\n              content: res.data.msg,\n              showCancel: false,\n            });\n          }else {\n            wx.showModal({\n              title: '提交成功',\n              content: \"谢谢您的反馈\",\n              showCancel: false,\n              success: function (res) {\n                wx.navigateBack({\n                  delta:1\n                })\n              },\n            });\n          }\n        }\n      })\n    }else{\n      wx.showModal({\n        title: '提交失败',\n        content: '请选择故障的类型',\n        showCancel:false,\n      });\n    }\n    \n  },\n// 选择故障车周围环境图 拍照或选择相册\n  bindCamera: function(){\n    wx.chooseImage({\n      count: 4, \n      sizeType: ['original', 'compressed'],\n      sourceType: ['album', 'camera'], \n      success: (res) => {\n        let tfps = res.tempFilePaths;\n        let _picUrls = this.data.picUrls;\n        for(let item of tfps){\n          _picUrls.push(item);\n          this.setData({\n            picUrls: _picUrls,\n            actionText: \"+\"\n          });\n        };\n        var tempFilePath = res.tempFilePaths[0];\n        new AV.File('pictrue', {\n          blob: {\n            uri: tempFilePath,\n          },\n        }).save().then(\n          file => console.log(file.url())\n        ).catch(console.error);\n      }\n    })\n  },\n// 删除选择的故障车周围环境图\n  delPic: function(e){\n    let index = e.target.dataset.index;\n    let _picUrls = this.data.picUrls;\n    _picUrls.splice(index,1);\n    this.setData({\n      picUrls: _picUrls\n    })\n  }\n})"
  },
  {
    "path": "ofo 无微信支付/pages/warn/index.json",
    "content": "{}"
  },
  {
    "path": "ofo 无微信支付/pages/warn/index.wxml",
    "content": "<!--pages/warn/index.wxml-->\n<view class=\"container\">\n    <view class=\"choose\">\n        <view class=\"title\">请选择故障类型</view> \n        <checkbox-group bindchange=\"checkboxChange\" class=\"choose-grids\">\n            <block wx:for=\"{{itemsValue}}\" wx:key=\"{{item}}\">\n                <view class=\"grid\">\n                    <checkbox value=\"{{item.id}}\" checked=\"{{item.checked}}\" color=\"#b9dd08\" />{{item.value}}\n                </view>\n            </block>\n        </checkbox-group>        \n    </view>\n    <view class=\"action\">\n        <view class=\"title\">拍摄单车周围环境，便于维修师傅找车</view>\n        <view class=\"action-photo\">\n        <block wx:for=\"{{picUrls}}\" wx:key=\"{{item}}\" wx:index=\"{{index}}\">\n            <image src=\"{{item}}\"><icon type=\"cancel\" data-index=\"{{index}}\" color=\"red\" size=\"18\" class =\"del\" bindtap=\"delPic\" /></image>\n        </block>\n            <text class=\"add\" bindtap=\"bindCamera\">{{actionText}}</text>\n        </view>\n        <view class=\"action-input\">\n            <input bindinput=\"numberChange\" name=\"number\" placeholder=\"车牌号（车牌损坏不用填）\" />\n            <input bindinput=\"descChange\" name=\"desc\" placeholder=\"备注\" />            \n        </view>\n        <view class=\"action-submit\">\n            <button class=\"submit-btn\" type=\"default\" loading=\"{{loading}}\" bindtap=\"formSubmit\" style=\"background-color: {{btnBgc}}\">提交</button>\n        </view>\n    </view>\n</view>\n\n"
  },
  {
    "path": "ofo 无微信支付/pages/warn/index.wxss",
    "content": "/* pages/wallet/index.wxss */\n.choose{\n\tbackground-color: #fff;\n}\n.choose-grids{\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tjustify-content: space-around;\n\tpadding: 50rpx;\n}\n.choose-grids .grid{\n\twidth: 45%;\n\theight: 100rpx;\n\tmargin-top: 36rpx;\n\tborder-radius: 6rpx;\n\tline-height: 100rpx;\n\ttext-align: center;\n\tborder: 2rpx solid #b9dd08;\n}\n.choose-grids .grid:first-child,\n.choose-grids .grid:nth-of-type(2){\n\tmargin-top: 0;\n}\n.action .action-photo{\n\tbackground-color: #fff;\n\tpadding: 40rpx 0px 40rpx 50rpx;\n}\n.action .action-photo image{\n\tposition: relative;\n\tdisplay: inline-block;\n\twidth: 120rpx;\n\theight: 120rpx;\n\toverflow: visible;\n\tmargin-left: 25rpx;\n}\n.action .action-photo image icon.del{\n\tdisplay: block;\n\tposition: absolute;\n\ttop: -20rpx;\n\tright: -20rpx;\n}\n.action .action-photo text.add{\n\tdisplay: inline-block;\n\twidth: 120rpx;\n\theight: 120rpx;\n\tline-height: 120rpx;\n\ttext-align: center;\n\tfont-size: 24rpx;\n\tcolor: #ccc;\n\tborder: 2rpx dotted #ccc;\n\tmargin-left: 25rpx;\n\tvertical-align: top;\n}\n.action .action-input{\n\tpadding-left: 50rpx;\n\tmargin-top: 30rpx;\n\tbackground-color: #fff;\n}\n.action .action-input input{\n\twidth: 90%;\n\tpadding-top: 40rpx;\n\tpadding-bottom: 40rpx;\n}\n.action .action-input input:first-child{\n\tborder-bottom: 2rpx solid #ccc;\n\tpadding-bottom: 20rpx;\n}\n.action .action-input input:last-child{\n\tpadding-top: 20rpx;\n}\n.action .action-submit{\n\tpadding: 40rpx 40rpx;\n\tbackground-color: #f2f2f2;\n}\n\n"
  },
  {
    "path": "ofo 无微信支付/project.config.json",
    "content": "{\n\t\"description\": \"项目配置文件。\",\n\t\"setting\": {\n\t\t\"urlCheck\": true,\n\t\t\"es6\": true,\n\t\t\"postcss\": true,\n\t\t\"minified\": true,\n\t\t\"newFeature\": true\n\t},\n\t\"compileType\": \"miniprogram\",\n\t\"libVersion\": \"1.6.6\",\n\t\"appid\": \"wx0c0338b196a35915\",\n\t\"projectname\": \"ofo%E5%89%AF%E6%9C%AC\",\n\t\"condition\": {\n\t\t\"search\": {\n\t\t\t\"current\": -1,\n\t\t\t\"list\": []\n\t\t},\n\t\t\"conversation\": {\n\t\t\t\"current\": -1,\n\t\t\t\"list\": []\n\t\t},\n\t\t\"miniprogram\": {\n\t\t\t\"current\": -1,\n\t\t\t\"list\": []\n\t\t}\n\t}\n}"
  },
  {
    "path": "ofo 无微信支付/utils/av-weapp-min.js",
    "content": "!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define([],t):\"object\"==typeof exports?exports.AV=t():e.AV=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,\"a\",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p=\"\",t(t.s=31)}([function(e,t,n){var r,i;(function(){function n(e){function t(t,n,r,i,o,s){for(;o>=0&&o<s;o+=e){var a=i?i[o]:o;r=n(r,t[a],a,t)}return r}return function(n,r,i,o){r=S(r,o,4);var s=!C(n)&&O.keys(n),a=(s||n).length,u=e>0?0:a-1;return arguments.length<3&&(i=n[s?s[u]:u],u+=e),t(n,r,i,s,u,a)}}function o(e){return function(t,n,r){n=E(n,r);for(var i=x(t),o=e>0?0:i-1;o>=0&&o<i;o+=e)if(n(t[o],o,t))return o;return-1}}function s(e,t,n){return function(r,i,o){var s=0,a=x(r);if(\"number\"==typeof o)e>0?s=o>=0?o:Math.max(o+a,s):a=o>=0?Math.min(o+1,a):o+a+1;else if(n&&o&&a)return o=n(r,i),r[o]===i?o:-1;if(i!==i)return o=t(p.call(r,s,a),O.isNaN),o>=0?o+s:-1;for(o=e>0?s:a-1;o>=0&&o<a;o+=e)if(r[o]===i)return o;return-1}}function a(e,t){var n=P.length,r=e.constructor,i=O.isFunction(r)&&r.prototype||h,o=\"constructor\";for(O.has(e,o)&&!O.contains(t,o)&&t.push(o);n--;)o=P[n],o in e&&e[o]!==i[o]&&!O.contains(t,o)&&t.push(o)}var u=this,c=u._,l=Array.prototype,h=Object.prototype,f=Function.prototype,d=l.push,p=l.slice,_=h.toString,v=h.hasOwnProperty,y=Array.isArray,m=Object.keys,g=f.bind,b=Object.create,w=function(){},O=function(e){return e instanceof O?e:this instanceof O?void(this._wrapped=e):new O(e)};\"undefined\"!=typeof e&&e.exports&&(t=e.exports=O),t._=O,O.VERSION=\"1.8.3\";var S=function(e,t,n){if(void 0===t)return e;switch(null==n?3:n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)};case 4:return function(n,r,i,o){return e.call(t,n,r,i,o)}}return function(){return e.apply(t,arguments)}},E=function(e,t,n){return null==e?O.identity:O.isFunction(e)?S(e,t,n):O.isObject(e)?O.matcher(e):O.property(e)};O.iteratee=function(e,t){return E(e,t,1/0)};var A=function(e,t){return function(n){var r=arguments.length;if(r<2||null==n)return n;for(var i=1;i<r;i++)for(var o=arguments[i],s=e(o),a=s.length,u=0;u<a;u++){var c=s[u];t&&void 0!==n[c]||(n[c]=o[c])}return n}},T=function(e){if(!O.isObject(e))return{};if(b)return b(e);w.prototype=e;var t=new w;return w.prototype=null,t},j=function(e){return function(t){return null==t?void 0:t[e]}},N=Math.pow(2,53)-1,x=j(\"length\"),C=function(e){var t=x(e);return\"number\"==typeof t&&t>=0&&t<=N};O.each=O.forEach=function(e,t,n){t=S(t,n);var r,i;if(C(e))for(r=0,i=e.length;r<i;r++)t(e[r],r,e);else{var o=O.keys(e);for(r=0,i=o.length;r<i;r++)t(e[o[r]],o[r],e)}return e},O.map=O.collect=function(e,t,n){t=E(t,n);for(var r=!C(e)&&O.keys(e),i=(r||e).length,o=Array(i),s=0;s<i;s++){var a=r?r[s]:s;o[s]=t(e[a],a,e)}return o},O.reduce=O.foldl=O.inject=n(1),O.reduceRight=O.foldr=n(-1),O.find=O.detect=function(e,t,n){var r;if(r=C(e)?O.findIndex(e,t,n):O.findKey(e,t,n),void 0!==r&&r!==-1)return e[r]},O.filter=O.select=function(e,t,n){var r=[];return t=E(t,n),O.each(e,function(e,n,i){t(e,n,i)&&r.push(e)}),r},O.reject=function(e,t,n){return O.filter(e,O.negate(E(t)),n)},O.every=O.all=function(e,t,n){t=E(t,n);for(var r=!C(e)&&O.keys(e),i=(r||e).length,o=0;o<i;o++){var s=r?r[o]:o;if(!t(e[s],s,e))return!1}return!0},O.some=O.any=function(e,t,n){t=E(t,n);for(var r=!C(e)&&O.keys(e),i=(r||e).length,o=0;o<i;o++){var s=r?r[o]:o;if(t(e[s],s,e))return!0}return!1},O.contains=O.includes=O.include=function(e,t,n,r){return C(e)||(e=O.values(e)),(\"number\"!=typeof n||r)&&(n=0),O.indexOf(e,t,n)>=0},O.invoke=function(e,t){var n=p.call(arguments,2),r=O.isFunction(t);return O.map(e,function(e){var i=r?t:e[t];return null==i?i:i.apply(e,n)})},O.pluck=function(e,t){return O.map(e,O.property(t))},O.where=function(e,t){return O.filter(e,O.matcher(t))},O.findWhere=function(e,t){return O.find(e,O.matcher(t))},O.max=function(e,t,n){var r,i,o=-(1/0),s=-(1/0);if(null==t&&null!=e){e=C(e)?e:O.values(e);for(var a=0,u=e.length;a<u;a++)r=e[a],r>o&&(o=r)}else t=E(t,n),O.each(e,function(e,n,r){i=t(e,n,r),(i>s||i===-(1/0)&&o===-(1/0))&&(o=e,s=i)});return o},O.min=function(e,t,n){var r,i,o=1/0,s=1/0;if(null==t&&null!=e){e=C(e)?e:O.values(e);for(var a=0,u=e.length;a<u;a++)r=e[a],r<o&&(o=r)}else t=E(t,n),O.each(e,function(e,n,r){i=t(e,n,r),(i<s||i===1/0&&o===1/0)&&(o=e,s=i)});return o},O.shuffle=function(e){for(var t,n=C(e)?e:O.values(e),r=n.length,i=Array(r),o=0;o<r;o++)t=O.random(0,o),t!==o&&(i[o]=i[t]),i[t]=n[o];return i},O.sample=function(e,t,n){return null==t||n?(C(e)||(e=O.values(e)),e[O.random(e.length-1)]):O.shuffle(e).slice(0,Math.max(0,t))},O.sortBy=function(e,t,n){return t=E(t,n),O.pluck(O.map(e,function(e,n,r){return{value:e,index:n,criteria:t(e,n,r)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||void 0===n)return 1;if(n<r||void 0===r)return-1}return e.index-t.index}),\"value\")};var k=function(e){return function(t,n,r){var i={};return n=E(n,r),O.each(t,function(r,o){var s=n(r,o,t);e(i,r,s)}),i}};O.groupBy=k(function(e,t,n){O.has(e,n)?e[n].push(t):e[n]=[t]}),O.indexBy=k(function(e,t,n){e[n]=t}),O.countBy=k(function(e,t,n){O.has(e,n)?e[n]++:e[n]=1}),O.toArray=function(e){return e?O.isArray(e)?p.call(e):C(e)?O.map(e,O.identity):O.values(e):[]},O.size=function(e){return null==e?0:C(e)?e.length:O.keys(e).length},O.partition=function(e,t,n){t=E(t,n);var r=[],i=[];return O.each(e,function(e,n,o){(t(e,n,o)?r:i).push(e)}),[r,i]},O.first=O.head=O.take=function(e,t,n){if(null!=e)return null==t||n?e[0]:O.initial(e,e.length-t)},O.initial=function(e,t,n){return p.call(e,0,Math.max(0,e.length-(null==t||n?1:t)))},O.last=function(e,t,n){if(null!=e)return null==t||n?e[e.length-1]:O.rest(e,Math.max(0,e.length-t))},O.rest=O.tail=O.drop=function(e,t,n){return p.call(e,null==t||n?1:t)},O.compact=function(e){return O.filter(e,O.identity)};var U=function(e,t,n,r){for(var i=[],o=0,s=r||0,a=x(e);s<a;s++){var u=e[s];if(C(u)&&(O.isArray(u)||O.isArguments(u))){t||(u=U(u,t,n));var c=0,l=u.length;for(i.length+=l;c<l;)i[o++]=u[c++]}else n||(i[o++]=u)}return i};O.flatten=function(e,t){return U(e,t,!1)},O.without=function(e){return O.difference(e,p.call(arguments,1))},O.uniq=O.unique=function(e,t,n,r){O.isBoolean(t)||(r=n,n=t,t=!1),null!=n&&(n=E(n,r));for(var i=[],o=[],s=0,a=x(e);s<a;s++){var u=e[s],c=n?n(u,s,e):u;t?(s&&o===c||i.push(u),o=c):n?O.contains(o,c)||(o.push(c),i.push(u)):O.contains(i,u)||i.push(u)}return i},O.union=function(){return O.uniq(U(arguments,!0,!0))},O.intersection=function(e){for(var t=[],n=arguments.length,r=0,i=x(e);r<i;r++){var o=e[r];if(!O.contains(t,o)){for(var s=1;s<n&&O.contains(arguments[s],o);s++);s===n&&t.push(o)}}return t},O.difference=function(e){var t=U(arguments,!0,!0,1);return O.filter(e,function(e){return!O.contains(t,e)})},O.zip=function(){return O.unzip(arguments)},O.unzip=function(e){for(var t=e&&O.max(e,x).length||0,n=Array(t),r=0;r<t;r++)n[r]=O.pluck(e,r);return n},O.object=function(e,t){for(var n={},r=0,i=x(e);r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},O.findIndex=o(1),O.findLastIndex=o(-1),O.sortedIndex=function(e,t,n,r){n=E(n,r,1);for(var i=n(t),o=0,s=x(e);o<s;){var a=Math.floor((o+s)/2);n(e[a])<i?o=a+1:s=a}return o},O.indexOf=s(1,O.findIndex,O.sortedIndex),O.lastIndexOf=s(-1,O.findLastIndex),O.range=function(e,t,n){null==t&&(t=e||0,e=0),n=n||1;for(var r=Math.max(Math.ceil((t-e)/n),0),i=Array(r),o=0;o<r;o++,e+=n)i[o]=e;return i};var I=function(e,t,n,r,i){if(!(r instanceof t))return e.apply(n,i);var o=T(e.prototype),s=e.apply(o,i);return O.isObject(s)?s:o};O.bind=function(e,t){if(g&&e.bind===g)return g.apply(e,p.call(arguments,1));if(!O.isFunction(e))throw new TypeError(\"Bind must be called on a function\");var n=p.call(arguments,2),r=function(){return I(e,r,t,this,n.concat(p.call(arguments)))};return r},O.partial=function(e){var t=p.call(arguments,1),n=function(){for(var r=0,i=t.length,o=Array(i),s=0;s<i;s++)o[s]=t[s]===O?arguments[r++]:t[s];for(;r<arguments.length;)o.push(arguments[r++]);return I(e,n,this,this,o)};return n},O.bindAll=function(e){var t,n,r=arguments.length;if(r<=1)throw new Error(\"bindAll must be passed function names\");for(t=1;t<r;t++)n=arguments[t],e[n]=O.bind(e[n],e);return e},O.memoize=function(e,t){var n=function(r){var i=n.cache,o=\"\"+(t?t.apply(this,arguments):r);return O.has(i,o)||(i[o]=e.apply(this,arguments)),i[o]};return n.cache={},n},O.delay=function(e,t){var n=p.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},O.defer=O.partial(O.delay,O,1),O.throttle=function(e,t,n){var r,i,o,s=null,a=0;n||(n={});var u=function(){a=n.leading===!1?0:O.now(),s=null,o=e.apply(r,i),s||(r=i=null)};return function(){var c=O.now();a||n.leading!==!1||(a=c);var l=t-(c-a);return r=this,i=arguments,l<=0||l>t?(s&&(clearTimeout(s),s=null),a=c,o=e.apply(r,i),s||(r=i=null)):s||n.trailing===!1||(s=setTimeout(u,l)),o}},O.debounce=function(e,t,n){var r,i,o,s,a,u=function(){var c=O.now()-s;c<t&&c>=0?r=setTimeout(u,t-c):(r=null,n||(a=e.apply(o,i),r||(o=i=null)))};return function(){o=this,i=arguments,s=O.now();var c=n&&!r;return r||(r=setTimeout(u,t)),c&&(a=e.apply(o,i),o=i=null),a}},O.wrap=function(e,t){return O.partial(t,e)},O.negate=function(e){return function(){return!e.apply(this,arguments)}},O.compose=function(){var e=arguments,t=e.length-1;return function(){for(var n=t,r=e[t].apply(this,arguments);n--;)r=e[n].call(this,r);return r}},O.after=function(e,t){return function(){if(--e<1)return t.apply(this,arguments)}},O.before=function(e,t){var n;return function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=null),n}},O.once=O.partial(O.before,2);var R=!{toString:null}.propertyIsEnumerable(\"toString\"),P=[\"valueOf\",\"isPrototypeOf\",\"toString\",\"propertyIsEnumerable\",\"hasOwnProperty\",\"toLocaleString\"];O.keys=function(e){if(!O.isObject(e))return[];if(m)return m(e);var t=[];for(var n in e)O.has(e,n)&&t.push(n);return R&&a(e,t),t},O.allKeys=function(e){if(!O.isObject(e))return[];var t=[];for(var n in e)t.push(n);return R&&a(e,t),t},O.values=function(e){for(var t=O.keys(e),n=t.length,r=Array(n),i=0;i<n;i++)r[i]=e[t[i]];return r},O.mapObject=function(e,t,n){t=E(t,n);for(var r,i=O.keys(e),o=i.length,s={},a=0;a<o;a++)r=i[a],s[r]=t(e[r],r,e);return s},O.pairs=function(e){for(var t=O.keys(e),n=t.length,r=Array(n),i=0;i<n;i++)r[i]=[t[i],e[t[i]]];return r},O.invert=function(e){for(var t={},n=O.keys(e),r=0,i=n.length;r<i;r++)t[e[n[r]]]=n[r];return t},O.functions=O.methods=function(e){var t=[];for(var n in e)O.isFunction(e[n])&&t.push(n);return t.sort()},O.extend=A(O.allKeys),O.extendOwn=O.assign=A(O.keys),O.findKey=function(e,t,n){t=E(t,n);for(var r,i=O.keys(e),o=0,s=i.length;o<s;o++)if(r=i[o],t(e[r],r,e))return r},O.pick=function(e,t,n){var r,i,o={},s=e;if(null==s)return o;O.isFunction(t)?(i=O.allKeys(s),r=S(t,n)):(i=U(arguments,!1,!1,1),r=function(e,t,n){return t in n},s=Object(s));for(var a=0,u=i.length;a<u;a++){var c=i[a],l=s[c];r(l,c,s)&&(o[c]=l)}return o},O.omit=function(e,t,n){if(O.isFunction(t))t=O.negate(t);else{var r=O.map(U(arguments,!1,!1,1),String);t=function(e,t){return!O.contains(r,t)}}return O.pick(e,t,n)},O.defaults=A(O.allKeys,!0),O.create=function(e,t){var n=T(e);return t&&O.extendOwn(n,t),n},O.clone=function(e){return O.isObject(e)?O.isArray(e)?e.slice():O.extend({},e):e},O.tap=function(e,t){return t(e),e},O.isMatch=function(e,t){var n=O.keys(t),r=n.length;if(null==e)return!r;for(var i=Object(e),o=0;o<r;o++){var s=n[o];if(t[s]!==i[s]||!(s in i))return!1}return!0};var D=function(e,t,n,r){if(e===t)return 0!==e||1/e===1/t;if(null==e||null==t)return e===t;e instanceof O&&(e=e._wrapped),t instanceof O&&(t=t._wrapped);var i=_.call(e);if(i!==_.call(t))return!1;switch(i){case\"[object RegExp]\":case\"[object String]\":return\"\"+e==\"\"+t;case\"[object Number]\":return+e!==+e?+t!==+t:0===+e?1/+e===1/t:+e===+t;case\"[object Date]\":case\"[object Boolean]\":return+e===+t}var o=\"[object Array]\"===i;if(!o){if(\"object\"!=typeof e||\"object\"!=typeof t)return!1;var s=e.constructor,a=t.constructor;if(s!==a&&!(O.isFunction(s)&&s instanceof s&&O.isFunction(a)&&a instanceof a)&&\"constructor\"in e&&\"constructor\"in t)return!1}n=n||[],r=r||[];for(var u=n.length;u--;)if(n[u]===e)return r[u]===t;if(n.push(e),r.push(t),o){if(u=e.length,u!==t.length)return!1;for(;u--;)if(!D(e[u],t[u],n,r))return!1}else{var c,l=O.keys(e);if(u=l.length,O.keys(t).length!==u)return!1;for(;u--;)if(c=l[u],!O.has(t,c)||!D(e[c],t[c],n,r))return!1}return n.pop(),r.pop(),!0};O.isEqual=function(e,t){return D(e,t)},O.isEmpty=function(e){return null==e||(C(e)&&(O.isArray(e)||O.isString(e)||O.isArguments(e))?0===e.length:0===O.keys(e).length)},O.isElement=function(e){return!(!e||1!==e.nodeType)},O.isArray=y||function(e){return\"[object Array]\"===_.call(e)},O.isObject=function(e){var t=typeof e;return\"function\"===t||\"object\"===t&&!!e},O.each([\"Arguments\",\"Function\",\"String\",\"Number\",\"Date\",\"RegExp\",\"Error\"],function(e){O[\"is\"+e]=function(t){return _.call(t)===\"[object \"+e+\"]\"}}),O.isArguments(arguments)||(O.isArguments=function(e){return O.has(e,\"callee\")}),\"function\"!=typeof/./&&\"object\"!=typeof Int8Array&&(O.isFunction=function(e){return\"function\"==typeof e||!1}),O.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},O.isNaN=function(e){return O.isNumber(e)&&e!==+e},O.isBoolean=function(e){return e===!0||e===!1||\"[object Boolean]\"===_.call(e)},O.isNull=function(e){return null===e},O.isUndefined=function(e){return void 0===e},O.has=function(e,t){return null!=e&&v.call(e,t)},O.noConflict=function(){return u._=c,this},O.identity=function(e){return e},O.constant=function(e){return function(){return e}},O.noop=function(){},O.property=j,O.propertyOf=function(e){return null==e?function(){}:function(t){return e[t]}},O.matcher=O.matches=function(e){return e=O.extendOwn({},e),function(t){return O.isMatch(t,e)}},O.times=function(e,t,n){var r=Array(Math.max(0,e));t=S(t,n,1);for(var i=0;i<e;i++)r[i]=t(i);return r},O.random=function(e,t){return null==t&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))},O.now=Date.now||function(){return(new Date).getTime()};var L={\"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\",\"'\":\"&#x27;\",\"`\":\"&#x60;\"},q=O.invert(L),M=function(e){var t=function(t){return e[t]},n=\"(?:\"+O.keys(e).join(\"|\")+\")\",r=RegExp(n),i=RegExp(n,\"g\");return function(e){return e=null==e?\"\":\"\"+e,r.test(e)?e.replace(i,t):e}};O.escape=M(L),O.unescape=M(q),O.result=function(e,t,n){var r=null==e?void 0:e[t];return void 0===r&&(r=n),O.isFunction(r)?r.call(e):r};var F=0;O.uniqueId=function(e){var t=++F+\"\";return e?e+t:t},O.templateSettings={evaluate:/<%([\\s\\S]+?)%>/g,interpolate:/<%=([\\s\\S]+?)%>/g,escape:/<%-([\\s\\S]+?)%>/g};var J=/(.)^/,B={\"'\":\"'\",\"\\\\\":\"\\\\\",\"\\r\":\"r\",\"\\n\":\"n\",\"\\u2028\":\"u2028\",\"\\u2029\":\"u2029\"},W=/\\\\|'|\\r|\\n|\\u2028|\\u2029/g,V=function(e){return\"\\\\\"+B[e]};O.template=function(e,t,n){!t&&n&&(t=n),t=O.defaults({},t,O.templateSettings);var r=RegExp([(t.escape||J).source,(t.interpolate||J).source,(t.evaluate||J).source].join(\"|\")+\"|$\",\"g\"),i=0,o=\"__p+='\";e.replace(r,function(t,n,r,s,a){return o+=e.slice(i,a).replace(W,V),i=a+t.length,n?o+=\"'+\\n((__t=(\"+n+\"))==null?'':_.escape(__t))+\\n'\":r?o+=\"'+\\n((__t=(\"+r+\"))==null?'':__t)+\\n'\":s&&(o+=\"';\\n\"+s+\"\\n__p+='\"),t}),o+=\"';\\n\",t.variable||(o=\"with(obj||{}){\\n\"+o+\"}\\n\"),o=\"var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\\n\"+o+\"return __p;\\n\";try{var s=new Function(t.variable||\"obj\",\"_\",o)}catch(e){throw e.source=o,e}var a=function(e){return s.call(this,e,O)},u=t.variable||\"obj\";return a.source=\"function(\"+u+\"){\\n\"+o+\"}\",a},O.chain=function(e){var t=O(e);return t._chain=!0,t};var Q=function(e,t){return e._chain?O(t).chain():t};O.mixin=function(e){O.each(O.functions(e),function(t){var n=O[t]=e[t];O.prototype[t]=function(){var e=[this._wrapped];return d.apply(e,arguments),Q(this,n.apply(O,e))}})},O.mixin(O),O.each([\"pop\",\"push\",\"reverse\",\"shift\",\"sort\",\"splice\",\"unshift\"],function(e){var t=l[e];O.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),\"shift\"!==e&&\"splice\"!==e||0!==n.length||delete n[0],Q(this,n)}}),O.each([\"concat\",\"join\",\"slice\"],function(e){var t=l[e];O.prototype[e]=function(){return Q(this,t.apply(this._wrapped,arguments))}}),O.prototype.value=function(){return this._wrapped},O.prototype.valueOf=O.prototype.toJSON=O.prototype.value,O.prototype.toString=function(){return\"\"+this._wrapped},r=[],i=function(){return O}.apply(t,r),!(void 0!==i&&(e.exports=i))}).call(this)},function(e,t,n){\"use strict\";var r=(n(0),n(53).Promise);r._continueWhile=function(e,t){return e()?t().then(function(){return r._continueWhile(e,t)}):r.resolve()},e.exports=r},function(e,t,n){\"use strict\";var r=n(58),i=n(0),o=i.extend,s=n(1),a=n(3),u=n(6),c=n(4),l=c.getSessionToken,h=c.ajax,f=function(e,t){var n=(new Date).getTime(),i=r(n+e);return t?i+\",\"+n+\",master\":i+\",\"+n},d=function(e,t){t?e[\"X-LC-Sign\"]=f(u.applicationKey):e[\"X-LC-Key\"]=u.applicationKey},p=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=arguments[1],n={\"X-LC-Id\":u.applicationId,\"Content-Type\":\"application/json;charset=UTF-8\"},r=!1;return\"boolean\"==typeof e.useMasterKey?r=e.useMasterKey:\"boolean\"==typeof u._config.useMasterKey&&(r=u._config.useMasterKey),r?u.masterKey?t?n[\"X-LC-Sign\"]=f(u.masterKey,!0):n[\"X-LC-Key\"]=u.masterKey+\",master\":(console.warn(\"masterKey is not set, fall back to use appKey\"),d(n,t)):d(n,t),u.hookKey&&(n[\"X-LC-Hook-Key\"]=u.hookKey),null!==u._config.production&&(n[\"X-LC-Prod\"]=String(u._config.production)),n[\"X-LC-UA\"]=u._config.userAgent,s.resolve().then(function(){var t=l(e);if(t)n[\"X-LC-Session\"]=t;else if(!u._config.disableCurrentUser)return u.User.currentAsync().then(function(e){return e&&e._sessionToken&&(n[\"X-LC-Session\"]=e._sessionToken),n});return n})},_=function(e){var t=e.service,n=void 0===t?\"api\":t,r=e.version,i=void 0===r?\"1.1\":r,o=e.path,s=u._config.serverURLs[n];if(!s)throw new Error(\"undefined server URL for \"+n);return\"/\"!==s.charAt(s.length-1)&&(s+=\"/\"),s+=i,o&&(s+=o),s},v=function(e){return new s(function(t,n){var r={code:e.code||-1,error:e.message||e.responseText};if(e.response&&e.response.code)r=e.response;else if(e.responseText)try{r=JSON.parse(e.responseText)}catch(e){}n(new a(r.code,r.error))})},y=function(e){var t=e.service,n=e.version,r=e.method,i=e.path,o=e.query,s=e.data,a=void 0===s?{}:s,c=e.authOptions,l=e.signKey,f=void 0===l||l;if(!u.applicationId||!u.applicationKey&&!u.masterKey)throw new Error(\"Not initialized\");u._appRouter.refresh();var d=_({service:t,path:i,version:n});return p(c,f).then(function(e){return h({method:r,url:d,query:o,data:a,headers:e}).catch(v)})},m=function(e,t,n,r){var i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},s=arguments[5],a=arguments[6],u=\"\";if(e&&(u+=\"/\"+e),t&&(u+=\"/\"+t),n&&(u+=\"/\"+n),i&&i._fetchWhenSave)throw new Error(\"_fetchWhenSave should be in the query\");if(i&&i._where)throw new Error(\"_where should be in the query\");return r&&\"get\"===r.toLowerCase()&&(a=o({},a,i),i=null),y({method:r,path:u,query:a,data:i,authOptions:s})};u.request=y,e.exports={_request:m,request:y}},function(e,t,n){\"use strict\";function r(e,t){var n=new Error(t);return n.code=e,n}var i=n(0);i.extend(r,{OTHER_CAUSE:-1,INTERNAL_SERVER_ERROR:1,CONNECTION_FAILED:100,OBJECT_NOT_FOUND:101,INVALID_QUERY:102,INVALID_CLASS_NAME:103,MISSING_OBJECT_ID:104,INVALID_KEY_NAME:105,INVALID_POINTER:106,INVALID_JSON:107,COMMAND_UNAVAILABLE:108,NOT_INITIALIZED:109,INCORRECT_TYPE:111,INVALID_CHANNEL_NAME:112,PUSH_MISCONFIGURED:115,OBJECT_TOO_LARGE:116,OPERATION_FORBIDDEN:119,CACHE_MISS:120,INVALID_NESTED_KEY:121,INVALID_FILE_NAME:122,INVALID_ACL:123,TIMEOUT:124,INVALID_EMAIL_ADDRESS:125,MISSING_CONTENT_TYPE:126,MISSING_CONTENT_LENGTH:127,INVALID_CONTENT_LENGTH:128,FILE_TOO_LARGE:129,FILE_SAVE_ERROR:130,FILE_DELETE_ERROR:153,DUPLICATE_VALUE:137,INVALID_ROLE_NAME:139,EXCEEDED_QUOTA:140,SCRIPT_FAILED:141,VALIDATION_ERROR:142,INVALID_IMAGE_DATA:150,UNSAVED_FILE_ERROR:151,INVALID_PUSH_TIME_ERROR:152,USERNAME_MISSING:200,PASSWORD_MISSING:201,USERNAME_TAKEN:202,EMAIL_TAKEN:203,EMAIL_MISSING:204,EMAIL_NOT_FOUND:205,SESSION_MISSING:206,MUST_CREATE_USER_THROUGH_SIGNUP:207,ACCOUNT_ALREADY_LINKED:208,LINKED_ID_MISSING:250,INVALID_LINKED_SESSION:251,UNSUPPORTED_SERVICE:252,X_DOMAIN_REQUEST:602}),e.exports=r},function(e,t,n){\"use strict\";function r(e){var t=new RegExp(\"^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})T([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})(.([0-9]+))?Z$\"),n=t.exec(e);if(!n)return null;var r=n[1]||0,i=(n[2]||1)-1,o=n[3]||0,s=n[4]||0,a=n[5]||0,u=n[6]||0,c=n[8]||0;return new Date(Date.UTC(r,i,o,s,a,u,c))}var i=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},o=n(0),s=n(7),a=n(5)(\"leancloud:request\"),u=0,c=function(e){var t=e.method,n=e.url,r=e.query,o=e.data,c=e.headers,l=void 0===c?{}:c,h=e.onprogress,f=u++;a(\"request(\"+f+\")\",t,n,r,o,l);var d={};if(r)for(var p in r)\"object\"===i(r[p])?d[p]=JSON.stringify(r[p]):d[p]=r[p];return new Promise(function(e,r){var i=s(t,n).set(l).query(d).send(o);h&&i.on(\"progress\",h),i.end(function(t,n){return n&&a(\"response(\"+f+\")\",n.status,n.body||n.text,n.header),t?(n&&(t.statusCode=n.status,t.responseText=n.text,t.response=n.body),r(t)):e(n.body)})})},l=function(e){return o.isNull(e)||o.isUndefined(e)},h=function(e){return o.isArray(e)?e:void 0===e||null===e?[]:[e]},f=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.keys,n=e.include,r=e.includeACL,i={};return t&&(i.keys=h(t).join(\",\")),n&&(i.include=h(n).join(\",\")),r&&(i.returnACL=r),i},d=function(e){return e.sessionToken?e.sessionToken:e.user&&\"function\"==typeof e.user.getSessionToken?e.user.getSessionToken():void 0},p=function(e){return function(t){return e(t),t}},_=function(){},v=function(e,t,n){var r;return r=t&&t.hasOwnProperty(\"constructor\")?t.constructor:function(){e.apply(this,arguments)},o.extend(r,e),_.prototype=e.prototype,r.prototype=new _,t&&o.extend(r.prototype,t),n&&o.extend(r,n),r.prototype.constructor=r,r.__super__=e.prototype,r};e.exports={ajax:c,isNullOrUndefined:l,ensureArray:h,transformFetchOptions:f,getSessionToken:d,tap:p,inherits:v,parseDate:r}},function(e,t,n){function r(){return!(\"undefined\"==typeof window||!window||\"undefined\"==typeof window.process||\"renderer\"!==window.process.type)||(\"undefined\"!=typeof document&&document&&\"WebkitAppearance\"in document.documentElement.style||\"undefined\"!=typeof window&&window&&window.console&&(console.firebug||console.exception&&console.table)||\"undefined\"!=typeof navigator&&navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/)&&parseInt(RegExp.$1,10)>=31||\"undefined\"!=typeof navigator&&navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/))}function i(e){var n=this.useColors;if(e[0]=(n?\"%c\":\"\")+this.namespace+(n?\" %c\":\" \")+e[0]+(n?\"%c \":\" \")+\"+\"+t.humanize(this.diff),n){var r=\"color: \"+this.color;e.splice(1,0,r,\"color: inherit\");var i=0,o=0;e[0].replace(/%[a-zA-Z%]/g,function(e){\"%%\"!==e&&(i++,\"%c\"===e&&(o=i))}),e.splice(o,0,r)}}function o(){return\"object\"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function s(e){try{null==e?t.storage.removeItem(\"debug\"):t.storage.debug=e}catch(e){}}function a(){var e;try{e=t.storage.debug}catch(e){}return!e&&\"undefined\"!=typeof process&&\"env\"in process&&(e=process.env.DEBUG),e}function u(){try{return window.localStorage}catch(e){}}t=e.exports=n(52),t.log=o,t.formatArgs=i,t.save=s,t.load=a,t.useColors=r,t.storage=\"undefined\"!=typeof chrome&&\"undefined\"!=typeof chrome.storage?chrome.storage.local:u(),t.colors=[\"lightseagreen\",\"forestgreen\",\"goldenrod\",\"dodgerblue\",\"darkorchid\",\"crimson\"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(e){return\"[UnexpectedJSONParseError]: \"+e.message}},t.enable(a())},function(e,t,n){\"use strict\";(function(t){var r=n(0),i=n(43),o=n(4),s=o.inherits,a=o.parseDate,u=t.AV||{};u._config={userAgent:i,serverURLs:{},useMasterKey:!1,production:null},u._getAVPath=function(e){if(!u.applicationId)throw new Error(\"You need to call AV.initialize before using AV.\");if(e||(e=\"\"),!r.isString(e))throw new Error(\"Tried to get a localStorage path that wasn't a String.\");return\"/\"===e[0]&&(e=e.substring(1)),\"AV/\"+u.applicationId+\"/\"+e},u._installationId=null,u._getInstallationId=function(){if(u._installationId)return u.Promise.resolve(u._installationId);var e=u._getAVPath(\"installationId\");return u.localStorage.getItemAsync(e).then(function(t){if(u._installationId=t,u._installationId)return t;var n=function(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)};return u._installationId=n()+n()+\"-\"+n()+\"-\"+n()+\"-\"+n()+\"-\"+n()+n()+n(),u.localStorage.setItemAsync(e,u._installationId)})},u._parseDate=a,u._extend=function(e,t){var n=s(this,e,t);return n.extend=this.extend,n},u._encode=function(e,t,n){var i=!(arguments.length>3&&void 0!==arguments[3])||arguments[3];if(e instanceof u.Object){if(n)throw new Error(\"AV.Objects not allowed here\");return t&&!r.include(t,e)&&e._hasData?e._toFullJSON(t.concat(e),i):e._toPointer()}if(e instanceof u.ACL)return e.toJSON();if(r.isDate(e))return i?{__type:\"Date\",iso:e.toJSON()}:e.toJSON();if(e instanceof u.GeoPoint)return e.toJSON();if(r.isArray(e))return r.map(e,function(e){return u._encode(e,t,n,i)});if(r.isRegExp(e))return e.source;if(e instanceof u.Relation)return e.toJSON();if(e instanceof u.Op)return e.toJSON();if(e instanceof u.File){if(!e.url()&&!e.id)throw new Error(\"Tried to save an object containing an unsaved file.\");return e._toFullJSON(t,i)}return r.isObject(e)?r.mapObject(e,function(e,r){return u._encode(e,t,n,i)}):e},u._decode=function(e,t){if(!r.isObject(e)||r.isDate(e))return e;if(r.isArray(e))return r.map(e,function(e){return u._decode(e)});if(e instanceof u.Object)return e;if(e instanceof u.File)return e;if(e instanceof u.Op)return e;if(e instanceof u.GeoPoint)return e;if(e instanceof u.ACL)return e;if(\"ACL\"===t)return new u.ACL(e);if(e.__op)return u.Op._decode(e);var n;if(\"Pointer\"===e.__type){n=e.className;var i=u.Object._create(n);if(Object.keys(e).length>3){var o=r.clone(e);delete o.__type,delete o.className,i._finishFetch(o,!0)}else i._finishFetch({objectId:e.objectId},!1);return i}if(\"Object\"===e.__type){n=e.className;var s=r.clone(e);delete s.__type,delete s.className;var a=u.Object._create(n);return a._finishFetch(s,!0),a}if(\"Date\"===e.__type)return u._parseDate(e.iso);if(\"GeoPoint\"===e.__type)return new u.GeoPoint({latitude:e.latitude,longitude:e.longitude});if(\"Relation\"===e.__type){if(!t)throw new Error(\"key missing decoding a Relation\");var c=new u.Relation(null,t);return c.targetClassName=e.className,c}if(\"File\"===e.__type){var l=new u.File(e.name),h=r.clone(e);return delete h.__type,l._finishFetch(h),l}return r.mapObject(e,u._decode)},u.parseJSON=u._decode,u._encodeObjectOrArray=function(e){var t=function(e){return e&&e._toFullJSON&&(e=e._toFullJSON([])),r.mapObject(e,function(e){return u._encode(e,[])})};return r.isArray(e)?e.map(function(e){return t(e)}):t(e)},u._arrayEach=r.each,u._traverse=function(e,t,n){if(e instanceof u.Object){if(n=n||[],r.indexOf(n,e)>=0)return;return n.push(e),u._traverse(e.attributes,t,n),t(e)}return e instanceof u.Relation||e instanceof u.File?t(e):r.isArray(e)?(r.each(e,function(r,i){var o=u._traverse(r,t,n);o&&(e[i]=o)}),t(e)):r.isObject(e)?(u._each(e,function(r,i){var o=u._traverse(r,t,n);o&&(e[i]=o)}),t(e)):t(e)},u._objectEach=u._each=function(e,t){r.isObject(e)?r.each(r.keys(e),function(n){t(e[n],n)}):r.each(e,t)},e.exports=u}).call(t,n(8))},function(e,t,n){function r(){}function i(e){if(!_(e))return e;var t=[];for(var n in e)o(t,n,e[n]);return t.join(\"&\")}function o(e,t,n){if(null!=n)if(Array.isArray(n))n.forEach(function(n){o(e,t,n)});else if(_(n))for(var r in n)o(e,t+\"[\"+r+\"]\",n[r]);else e.push(encodeURIComponent(t)+\"=\"+encodeURIComponent(n));else null===n&&e.push(encodeURIComponent(t))}function s(e){for(var t,n,r={},i=e.split(\"&\"),o=0,s=i.length;o<s;++o)t=i[o],n=t.indexOf(\"=\"),n==-1?r[decodeURIComponent(t)]=\"\":r[decodeURIComponent(t.slice(0,n))]=decodeURIComponent(t.slice(n+1));return r}function a(e){var t,n,r,i,o=e.split(/\\r?\\n/),s={};o.pop();for(var a=0,u=o.length;a<u;++a)n=o[a],t=n.indexOf(\":\"),r=n.slice(0,t).toLowerCase(),i=b(n.slice(t+1)),s[r]=i;return s}function u(e){return/[\\/+]json\\b/.test(e)}function c(e){this.req=e,this.xhr=this.req.xhr,this.text=\"HEAD\"!=this.req.method&&(\"\"===this.xhr.responseType||\"text\"===this.xhr.responseType)||\"undefined\"==typeof this.xhr.responseType?this.xhr.responseText:null,this.statusText=this.req.xhr.statusText;var t=this.xhr.status;1223===t&&(t=204),this._setStatusProperties(t),this.header=this.headers=a(this.xhr.getAllResponseHeaders()),this.header[\"content-type\"]=this.xhr.getResponseHeader(\"content-type\"),this._setHeaderProperties(this.header),null===this.text&&e._responseType?this.body=this.xhr.response:this.body=\"HEAD\"!=this.req.method?this._parseBody(this.text?this.text:this.xhr.response):null}function l(e,t){var n=this;this._query=this._query||[],this.method=e,this.url=t,this.header={},this._header={},this.on(\"end\",function(){var e=null,t=null;try{t=new c(n)}catch(t){return e=new Error(\"Parser is unable to parse the response\"),e.parse=!0,e.original=t,n.xhr?(e.rawResponse=\"undefined\"==typeof n.xhr.responseType?n.xhr.responseText:n.xhr.response,e.status=n.xhr.status?n.xhr.status:null,e.statusCode=e.status):(e.rawResponse=null,e.status=null),n.callback(e)}n.emit(\"response\",t);var r;try{n._isResponseOK(t)||(r=new Error(t.statusText||\"Unsuccessful HTTP response\"),r.original=e,r.response=t,r.status=t.status)}catch(e){r=e}r?n.callback(r,t):n.callback(null,t)})}function h(e,t,n){var r=g(\"DELETE\",e);return\"function\"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r}var f;\"undefined\"!=typeof window?f=window:\"undefined\"!=typeof self?f=self:(console.warn(\"Using browser-only version of superagent in non-browser environment\"),f=this);var d=n(50),p=n(61),_=n(11),v=n(60),y=n(62),m=n(63),g=t=e.exports=function(e,n){return\"function\"==typeof n?new t.Request(\"GET\",e).end(n):1==arguments.length?new t.Request(\"GET\",e):new t.Request(e,n)};t.Request=l,g.getXHR=function(){if(!(!f.XMLHttpRequest||f.location&&\"file:\"==f.location.protocol&&f.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject(\"Microsoft.XMLHTTP\")}catch(e){}try{return new ActiveXObject(\"Msxml2.XMLHTTP.6.0\")}catch(e){}try{return new ActiveXObject(\"Msxml2.XMLHTTP.3.0\")}catch(e){}try{return new ActiveXObject(\"Msxml2.XMLHTTP\")}catch(e){}throw Error(\"Browser-only verison of superagent could not find XHR\")};var b=\"\".trim?function(e){return e.trim()}:function(e){return e.replace(/(^\\s*|\\s*$)/g,\"\")};g.serializeObject=i,g.parseString=s,g.types={html:\"text/html\",json:\"application/json\",xml:\"application/xml\",urlencoded:\"application/x-www-form-urlencoded\",form:\"application/x-www-form-urlencoded\",\"form-data\":\"application/x-www-form-urlencoded\"},g.serialize={\"application/x-www-form-urlencoded\":i,\"application/json\":JSON.stringify},g.parse={\"application/x-www-form-urlencoded\":s,\"application/json\":JSON.parse},y(c.prototype),c.prototype._parseBody=function(e){var t=g.parse[this.type];return this.req._parser?this.req._parser(this,e):(!t&&u(this.type)&&(t=g.parse[\"application/json\"]),t&&e&&(e.length||e instanceof Object)?t(e):null)},c.prototype.toError=function(){var e=this.req,t=e.method,n=e.url,r=\"cannot \"+t+\" \"+n+\" (\"+this.status+\")\",i=new Error(r);return i.status=this.status,i.method=t,i.url=n,i},g.Response=c,d(l.prototype),p(l.prototype),\nl.prototype.type=function(e){return this.set(\"Content-Type\",g.types[e]||e),this},l.prototype.accept=function(e){return this.set(\"Accept\",g.types[e]||e),this},l.prototype.auth=function(e,t,n){switch(\"object\"==typeof t&&null!==t&&(n=t),n||(n={type:\"function\"==typeof btoa?\"basic\":\"auto\"}),n.type){case\"basic\":this.set(\"Authorization\",\"Basic \"+btoa(e+\":\"+t));break;case\"auto\":this.username=e,this.password=t;break;case\"bearer\":this.set(\"Authorization\",\"Bearer \"+e)}return this},l.prototype.query=function(e){return\"string\"!=typeof e&&(e=i(e)),e&&this._query.push(e),this},l.prototype.attach=function(e,t,n){if(t){if(this._data)throw Error(\"superagent can't mix .send() and .attach()\");this._getFormData().append(e,t,n||t.name)}return this},l.prototype._getFormData=function(){return this._formData||(this._formData=new f.FormData),this._formData},l.prototype.callback=function(e,t){if(this._maxRetries&&this._retries++<this._maxRetries&&m(e,t))return this._retry();var n=this._callback;this.clearTimeout(),e&&(this._maxRetries&&(e.retries=this._retries-1),this.emit(\"error\",e)),n(e,t)},l.prototype.crossDomainError=function(){var e=new Error(\"Request has been terminated\\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.\");e.crossDomain=!0,e.status=this.status,e.method=this.method,e.url=this.url,this.callback(e)},l.prototype.buffer=l.prototype.ca=l.prototype.agent=function(){return console.warn(\"This is not supported in browser version of superagent\"),this},l.prototype.pipe=l.prototype.write=function(){throw Error(\"Streaming is not supported in browser version of superagent\")},l.prototype._appendQueryString=function(){var e=this._query.join(\"&\");if(e&&(this.url+=(this.url.indexOf(\"?\")>=0?\"&\":\"?\")+e),this._sort){var t=this.url.indexOf(\"?\");if(t>=0){var n=this.url.substring(t+1).split(\"&\");v(this._sort)?n.sort(this._sort):n.sort(),this.url=this.url.substring(0,t)+\"?\"+n.join(\"&\")}}},l.prototype._isHost=function(e){return e&&\"object\"==typeof e&&!Array.isArray(e)&&\"[object Object]\"!==Object.prototype.toString.call(e)},l.prototype.end=function(e){return this._endCalled&&console.warn(\"Warning: .end() was called twice. This is not supported in superagent\"),this._endCalled=!0,this._callback=e||r,this._appendQueryString(),this._end()},l.prototype._end=function(){var e=this,t=this.xhr=g.getXHR(),n=this._formData||this._data;this._setTimeouts(),t.onreadystatechange=function(){var n=t.readyState;if(n>=2&&e._responseTimeoutTimer&&clearTimeout(e._responseTimeoutTimer),4==n){var r;try{r=t.status}catch(e){r=0}if(!r){if(e.timedout||e._aborted)return;return e.crossDomainError()}e.emit(\"end\")}};var r=function(t,n){n.total>0&&(n.percent=n.loaded/n.total*100),n.direction=t,e.emit(\"progress\",n)};if(this.hasListeners(\"progress\"))try{t.onprogress=r.bind(null,\"download\"),t.upload&&(t.upload.onprogress=r.bind(null,\"upload\"))}catch(e){}try{this.username&&this.password?t.open(this.method,this.url,!0,this.username,this.password):t.open(this.method,this.url,!0)}catch(e){return this.callback(e)}if(this._withCredentials&&(t.withCredentials=!0),!this._formData&&\"GET\"!=this.method&&\"HEAD\"!=this.method&&\"string\"!=typeof n&&!this._isHost(n)){var i=this._header[\"content-type\"],o=this._serializer||g.serialize[i?i.split(\";\")[0]:\"\"];!o&&u(i)&&(o=g.serialize[\"application/json\"]),o&&(n=o(n))}for(var s in this.header)null!=this.header[s]&&this.header.hasOwnProperty(s)&&t.setRequestHeader(s,this.header[s]);return this._responseType&&(t.responseType=this._responseType),this.emit(\"request\",this),t.send(\"undefined\"!=typeof n?n:null),this},g.get=function(e,t,n){var r=g(\"GET\",e);return\"function\"==typeof t&&(n=t,t=null),t&&r.query(t),n&&r.end(n),r},g.head=function(e,t,n){var r=g(\"HEAD\",e);return\"function\"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r},g.options=function(e,t,n){var r=g(\"OPTIONS\",e);return\"function\"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r},g.del=h,g.delete=h,g.patch=function(e,t,n){var r=g(\"PATCH\",e);return\"function\"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r},g.post=function(e,t,n){var r=g(\"POST\",e);return\"function\"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r},g.put=function(e,t,n){var r=g(\"PUT\",e);return\"function\"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r}},function(e,t){var n;n=function(){return this}();try{n=n||Function(\"return this\")()||(0,eval)(\"this\")}catch(e){\"object\"==typeof window&&(n=window)}e.exports=n},function(e,t,n){\"use strict\";function r(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}var i=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},o=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,\"value\"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),s=function(){function e(){r(this,e),this._entries=[]}return o(e,[{key:\"append\",value:function(e,t){if(\"string\"!=typeof e)throw new TypeError(\"FormData name must be a string\");if(\"string\"!=typeof t&&(\"object\"!==(\"undefined\"==typeof t?\"undefined\":i(t))||\"string\"!=typeof t.uri))throw new TypeError(\"FormData value must be a string or { uri: tempFilePath }\");this._entries.push([e,t])}},{key:\"set\",value:function(e,t){var n=this.get(e);n?n[1]=t:this.append(e,t)}},{key:\"delete\",value:function(e){this._entries=this._entries.filter(function(t){return t[0]!==e})}},{key:\"entries\",value:function(){return this._entries}},{key:\"get\",value:function(e){return this._entries.find(function(t){return t[0]===e})}},{key:\"getAll\",value:function(e){return this._entries.filter(function(t){return t[0]===e})}},{key:\"has\",value:function(e){return this._entries.some(function(t){return t[0]===e})}},{key:\"keys\",value:function(){return this._entries.map(function(e){return e[0]})}},{key:\"values\",value:function(){return this._entries.map(function(e){return e[1]})}}]),e}();e.exports=s},function(e,t,n){\"use strict\";var r=t.createUniqueKey=\"undefined\"!=typeof Symbol?Symbol:function(e){return\"[[\"+e+\"_\"+Math.random().toFixed(8).slice(2)+\"]]\"};t.LISTENERS=r(\"listeners\"),t.CAPTURE=1,t.BUBBLE=2,t.ATTRIBUTE=3,t.newNode=function(e,t){return{listener:e,kind:t,next:null}}},function(e,t){function n(e){return null!==e&&\"object\"==typeof e}e.exports=n},function(e,t,n){\"use strict\";function r(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}var i=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,\"value\"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),o=function(){function e(){r(this,e)}return i(e,[{key:\"getItem\",value:function(e){return wx.getStorageSync(e)}},{key:\"setItem\",value:function(e,t){return wx.setStorageSync(e,t)}},{key:\"removeItem\",value:function(e){return this.setItem(e,\"\")}},{key:\"clear\",value:function(){return wx.clearStorageSync()}}]),e}();e.exports=new o},function(e,t,n){\"use strict\";e.exports={}},function(e,t,n){\"use strict\";function r(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}function i(e,t){if(!e)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return!t||\"object\"!=typeof t&&\"function\"!=typeof t?e:t}function o(e,t){if(\"function\"!=typeof t&&null!==t)throw new TypeError(\"Super expression must either be null or a function, not \"+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function s(e){\"\"!==e.message&&_&&(_._readyState=d,_.dispatchEvent({type:\"error\",message:e.errMsg}))}var a=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,\"value\"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),u=n(21),c=n(20),l=0,h=1,f=2,d=3,p=[\"open\",\"error\",\"message\",\"close\"],_=void 0,v=function(e){function t(e,n){if(r(this,t),!e)throw new TypeError(\"Failed to construct 'WebSocket': url required\");if(n)throw new Error(\"subprotocal not supported in weapp\");var o=i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return o._url=e,o._protocal=\"\",o._readyState=l,_&&_.dispatchEvent({type:\"close\"}),_=o,wx.onSocketOpen(function(e){_&&(_._readyState=h,_.dispatchEvent({type:\"open\"}))}),wx.onSocketError(s),wx.onSocketMessage(function(e){if(_){var t=e.data,n=e.origin,r=e.ports,i=e.source;_.dispatchEvent({data:t,origin:n,ports:r,source:i,type:\"message\"})}}),wx.onSocketClose(function(e){if(_){_._readyState=d;var t=e.code,n=e.reason,r=e.wasClean;_.dispatchEvent({code:t,reason:n,wasClean:r,type:\"close\"}),_=null}}),wx.connectSocket({url:e,fail:function(e){return setTimeout(function(){return s(e)},0)}}),o}return o(t,e),a(t,[{key:\"close\",value:function(){this.readyState===l&&console.warn(\"close WebSocket which is connecting might not work\"),wx.closeSocket()}},{key:\"send\",value:function(e){if(this.readyState!==h)throw new Error(\"INVALID_STATE_ERR\");if(\"string\"!=typeof e)throw new TypeError(\"only string typed data are supported\");wx.sendSocketMessage({data:e})}},{key:\"url\",get:function(){return this._url}},{key:\"protocal\",get:function(){return this._protocal}},{key:\"readyState\",get:function(){return this._readyState}}]),t}(c(p));u(v,{CONNECTING:l,OPEN:h,CLOSING:f,CLOSED:d}),e.exports=v},function(e,t,n){\"use strict\";function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}function o(e,t){if(!e)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return!t||\"object\"!=typeof t&&\"function\"!=typeof t?e:t}function s(e,t){if(\"function\"!=typeof t&&null!==t)throw new TypeError(\"Super expression must either be null or a function, not \"+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function a(e){this.status=e.statusCode,this.statusText=e.statusCode;var t=e.data;\"string\"!=typeof t&&(t=JSON.stringify(t)),this.responseText=this.response=t,this.readyState=v,this.dispatchEvent({type:\"readystatechange\"})}var u=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,\"value\"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),c=n(21),l=n(20),h=n(9),f=0,d=1,p=2,_=3,v=4,y=[\"abort\",\"error\",\"load\",\"loadstart\",\"progress\",\"timeout\",\"loadend\",\"readystatechange\"],m=function(e){function t(){i(this,t);var e=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return e.readyState=f,e._headers={},e}return s(t,e),u(t,[{key:\"abort\",value:function(){throw new Error(\"not supported in weapp\")}},{key:\"getAllResponseHeaders\",value:function(){return console.warn(\"getAllResponseHeaders always returns ''\"),\"\"}},{key:\"getResponseHeader\",value:function(e){return\"content-type\"===e?(console.warn(\"get content-type always returns 'application/json'\"),\"application/json\"):(console.warn(\"getResponseHeader always returns ''\"),\"\")}},{key:\"overrideMimeType\",value:function(){throw new Error(\"not supported in weapp\")}},{key:\"open\",value:function(e,t){var n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if(this.readyState!==f)throw new Error(\"request is already opened\");if(!n)throw new Error(\"sync request is not supported\");this._method=e,this._url=t,this.readyState=d,this.dispatchEvent({type:\"readystatechange\"})}},{key:\"setRequestHeader\",value:function(e,t){if(this.readyState!==d)throw new Error(\"request is not opened\");this._headers[e.toLowerCase()]=t}},{key:\"send\",value:function(e){var t=this;if(this.readyState!==d)throw new Error(\"request is not opened\");if(e instanceof h){var n=e.entries(),i=n.filter(function(e){return\"string\"!=typeof e[1]});if(0===i.length)throw new Error(\"Must specify a Blob field in FormData\");i.length>1&&console.warn(\"Only the first Blob will be send in Weapp\");var o=n.filter(function(e){return\"string\"==typeof e[1]}).reduce(function(e,t){return c(e,r({},t[0],t[1]))},{});wx.uploadFile({url:this._url,name:i[0][0],filePath:i[0][1].uri,formData:o,header:this._headers,success:a.bind(this),fail:function(e){t.status=0,t.readyState=v,t.dispatchEvent({type:\"readystatechange\"}),t.dispatchEvent({type:\"error\"})}})}else wx.request({url:this._url,data:e||\"\",method:this._method.toUpperCase(),header:this._headers,success:a.bind(this),fail:function(e){t.status=0,t.readyState=v,t.dispatchEvent({type:\"readystatechange\"}),t.dispatchEvent({type:\"error\"})}})}}]),t}(l(y));c(m,{UNSENT:f,OPENED:d,HEADERS_RECEIVED:p,LOADING:_,DONE:v}),e.exports=m},function(e,t,n){\"use strict\";var r=n(17),i=n(6),o=t.removeAsync=r.removeItemAsync.bind(r),s=function(e,t){try{e=JSON.parse(e)}catch(e){return null}if(e){var n=e.expiredAt&&e.expiredAt<Date.now();return n?o(t).then(function(){return null}):e.value}return null};t.getAsync=function(e){return e=\"AV/\"+i.applicationId+\"/\"+e,r.getItemAsync(e).then(function(t){return s(t,e)})},t.setAsync=function(e,t,n){var o={value:t};return\"number\"==typeof n&&(o.expiredAt=Date.now()+n),r.setItemAsync(\"AV/\"+i.applicationId+\"/\"+e,JSON.stringify(o))}},function(e,t,n){\"use strict\";var r=n(0),i=n(1),o=n(48),s=[\"getItem\",\"setItem\",\"removeItem\",\"clear\"];o.async?r(s).each(function(e){\"function\"!=typeof o[e]&&(o[e]=function(){var t=new Error(\"Synchronous API [\"+e+\"] is not available in this runtime.\");throw t.code=\"SYNC_API_NOT_AVAILABLE\",t})}):r(s).each(function(e){\"function\"==typeof o[e]&&(o[e+\"Async\"]=function(){return i.resolve(o[e].apply(o,arguments))})}),e.exports=o},function(e,t,n){\"use strict\";e.exports=\"3.0.0-beta.2\"},function(e,t){var n={utf8:{stringToBytes:function(e){return n.bin.stringToBytes(unescape(encodeURIComponent(e)))},bytesToString:function(e){return decodeURIComponent(escape(n.bin.bytesToString(e)))}},bin:{stringToBytes:function(e){for(var t=[],n=0;n<e.length;n++)t.push(255&e.charCodeAt(n));return t},bytesToString:function(e){for(var t=[],n=0;n<e.length;n++)t.push(String.fromCharCode(e[n]));return t.join(\"\")}}};e.exports=n},function(e,t,n){\"use strict\";var r=n(10),i=n(54),o=n(55),s=r.LISTENERS,a=r.CAPTURE,u=r.BUBBLE,c=r.ATTRIBUTE,l=r.newNode,h=i.defineCustomEventTarget,f=o.createEventWrapper,d=o.STOP_IMMEDIATE_PROPAGATION_FLAG,p=\"undefined\"!=typeof window&&\"undefined\"!=typeof window.EventTarget,_=e.exports=function e(){if(!(this instanceof e)){if(1===arguments.length&&Array.isArray(arguments[0]))return h(e,arguments[0]);if(arguments.length>0){for(var t=Array(arguments.length),n=0;n<arguments.length;++n)t[n]=arguments[n];return h(e,t)}throw new TypeError(\"Cannot call a class as a function\")}Object.defineProperty(this,s,{value:Object.create(null)})};_.prototype=Object.create((p?window.EventTarget:Object).prototype,{constructor:{value:_,writable:!0,configurable:!0},addEventListener:{value:function(e,t,n){if(null==t)return!1;if(\"function\"!=typeof t&&\"object\"!=typeof t)throw new TypeError('\"listener\" is not an object.');var r=n?a:u,i=this[s][e];if(null==i)return this[s][e]=l(t,r),!0;for(var o=null;null!=i;){if(i.listener===t&&i.kind===r)return!1;o=i,i=i.next}return o.next=l(t,r),!0},configurable:!0,writable:!0},removeEventListener:{value:function(e,t,n){if(null==t)return!1;for(var r=n?a:u,i=null,o=this[s][e];null!=o;){if(o.listener===t&&o.kind===r)return null==i?this[s][e]=o.next:i.next=o.next,!0;i=o,o=o.next}return!1},configurable:!0,writable:!0},dispatchEvent:{value:function(e){var t=this[s][e.type];if(null==t)return!0;for(var n=f(e,this);null!=t&&(\"function\"==typeof t.listener?t.listener.call(this,n):t.kind!==c&&\"function\"==typeof t.listener.handleEvent&&t.listener.handleEvent(n),!n[d]);)t=t.next;return!n.defaultPrevented},configurable:!0,writable:!0}})},function(e,t,n){\"use strict\";function r(e){if(null===e||void 0===e)throw new TypeError(\"Object.assign cannot be called with null or undefined\");return Object(e)}function i(){try{if(!Object.assign)return!1;var e=new String(\"abc\");if(e[5]=\"de\",\"5\"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t[\"_\"+String.fromCharCode(n)]=n;var r=Object.getOwnPropertyNames(t).map(function(e){return t[e]});if(\"0123456789\"!==r.join(\"\"))return!1;var i={};return\"abcdefghijklmnopqrst\".split(\"\").forEach(function(e){i[e]=e}),\"abcdefghijklmnopqrst\"===Object.keys(Object.assign({},i)).join(\"\")}catch(e){return!1}}var o=Object.getOwnPropertySymbols,s=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;e.exports=i()?Object.assign:function(e,t){for(var n,i,u=r(e),c=1;c<arguments.length;c++){n=Object(arguments[c]);for(var l in n)s.call(n,l)&&(u[l]=n[l]);if(o){i=o(n);for(var h=0;h<i.length;h++)a.call(n,i[h])&&(u[i[h]]=n[i[h]])}}return u}},function(e,t,n){\"use strict\";var r=n(24).polyfill;window=window||{},r(),r(window);try{localStorage=localStorage||n(12)}catch(e){}try{XMLHttpRequest=XMLHttpRequest||n(15)}catch(e){}try{FormData=FormData||n(9)}catch(e){}try{WebSocket=WebSocket||n(14)}catch(e){}try{navigator=navigator||n(13)}catch(e){}},function(e,t,n){\"use strict\";var r=n(6);r._=n(0),r.version=n(18),r.Promise=n(1),r.localStorage=n(17),r.Cache=n(16),r.Error=n(3),n(32),n(28)(r),n(30)(r),n(25)(r),n(35)(r),n(38)(r),n(29)(r),n(34)(r),n(39)(r),n(47)(r),n(37)(r),n(27)(r),n(36)(r),n(41)(r),n(40)(r),n(33)(r),e.exports=r},function(e,t,n){\"use strict\";(function(t){var r=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},i=n(12),o=n(15),s=n(9),a=n(14),u=n(13);e.exports={polyfill:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:t||window;if(\"object\"!==(\"undefined\"==typeof e?\"undefined\":r(e)))throw new Error(\"polyfill target is not an Object\");var n={localStorage:i,XMLHttpRequest:o,FormData:s,WebSocket:a,Object:Object,navigator:u};for(var c in n)e[c]||(e[c]=n[c])},localStorage:i,XMLHttpRequest:o,FormData:s,WebSocket:a}}).call(t,n(8))},function(e,t,n){\"use strict\";var r=n(0);e.exports=function(e){var t=\"*\";e.ACL=function(t){var n=this;if(n.permissionsById={},r.isObject(t))if(t instanceof e.User)n.setReadAccess(t,!0),n.setWriteAccess(t,!0);else{if(r.isFunction(t))throw new Error(\"AV.ACL() called with a function.  Did you forget ()?\");e._objectEach(t,function(t,i){if(!r.isString(i))throw new Error(\"Tried to create an ACL with an invalid userId.\");n.permissionsById[i]={},e._objectEach(t,function(e,t){if(\"read\"!==t&&\"write\"!==t)throw new Error(\"Tried to create an ACL with an invalid permission type.\");if(!r.isBoolean(e))throw new Error(\"Tried to create an ACL with an invalid permission value.\");n.permissionsById[i][t]=e})})}},e.ACL.prototype.toJSON=function(){return r.clone(this.permissionsById)},e.ACL.prototype._setAccess=function(t,n,i){if(n instanceof e.User?n=n.id:n instanceof e.Role&&(n=\"role:\"+n.getName()),!r.isString(n))throw new Error(\"userId must be a string.\");if(!r.isBoolean(i))throw new Error(\"allowed must be either true or false.\");var o=this.permissionsById[n];if(!o){if(!i)return;o={},this.permissionsById[n]=o}i?this.permissionsById[n][t]=!0:(delete o[t],r.isEmpty(o)&&delete this.permissionsById[n])},e.ACL.prototype._getAccess=function(t,n){n instanceof e.User?n=n.id:n instanceof e.Role&&(n=\"role:\"+n.getName());var r=this.permissionsById[n];return!!r&&!!r[t]},e.ACL.prototype.setReadAccess=function(e,t){this._setAccess(\"read\",e,t)},e.ACL.prototype.getReadAccess=function(e){return this._getAccess(\"read\",e)},e.ACL.prototype.setWriteAccess=function(e,t){this._setAccess(\"write\",e,t)},e.ACL.prototype.getWriteAccess=function(e){return this._getAccess(\"write\",e)},e.ACL.prototype.setPublicReadAccess=function(e){this.setReadAccess(t,e)},e.ACL.prototype.getPublicReadAccess=function(){return this.getReadAccess(t)},e.ACL.prototype.setPublicWriteAccess=function(e){this.setWriteAccess(t,e)},e.ACL.prototype.getPublicWriteAccess=function(){return this.getWriteAccess(t)},e.ACL.prototype.getRoleReadAccess=function(t){if(t instanceof e.Role&&(t=t.getName()),r.isString(t))return this.getReadAccess(\"role:\"+t);throw new Error(\"role must be a AV.Role or a String\")},e.ACL.prototype.getRoleWriteAccess=function(t){if(t instanceof e.Role&&(t=t.getName()),r.isString(t))return this.getWriteAccess(\"role:\"+t);throw new Error(\"role must be a AV.Role or a String\")},e.ACL.prototype.setRoleReadAccess=function(t,n){if(t instanceof e.Role&&(t=t.getName()),r.isString(t))return void this.setReadAccess(\"role:\"+t,n);throw new Error(\"role must be a AV.Role or a String\")},e.ACL.prototype.setRoleWriteAccess=function(t,n){if(t instanceof e.Role&&(t=t.getName()),r.isString(t))return void this.setWriteAccess(\"role:\"+t,n);throw new Error(\"role must be a AV.Role or a String\")}}},function(e,t,n){\"use strict\";function r(e){var t=this;this.AV=e,this.lockedUntil=0,s.getAsync(\"serverURLs\").then(function(e){if(!e)return t.lock(0);var n=e.serverURLs,r=e.lockedUntil;t.AV._setServerURLs(n,!1),t.lockedUntil=r}).catch(function(){return t.lock(0)})}var i=n(4),o=i.ajax,s=n(16);r.prototype.disable=function(){this.disabled=!0},r.prototype.lock=function(e){this.lockedUntil=Date.now()+e},r.prototype.refresh=function(){var e=this;if(!(this.disabled||Date.now()<this.lockedUntil)){this.lock(10);var t=\"https://app-router.leancloud.cn/2/route\";return o({method:\"get\",url:t,query:{appId:this.AV.applicationId}}).then(function(t){if(!e.disabled){var n=t.ttl;if(!n)throw new Error(\"missing ttl\");n*=1e3;var r=\"https://\",i={push:r+t.push_server,stats:r+t.stats_server,engine:r+t.engine_server,api:r+t.api_server};return e.AV._setServerURLs(i,!1),e.lock(n),s.setAsync(\"serverURLs\",{serverURLs:i,lockedUntil:e.lockedUntil},n)}}).catch(function(t){console.warn(\"refresh server URLs failed: \"+t.message),e.lock(600)})}},e.exports=r},function(e,t,n){\"use strict\";var r=n(0),i=n(2),o=i._request,s=i.request;e.exports=function(e){e.Cloud=e.Cloud||{},r.extend(e.Cloud,{run:function(t,n,r){return s({service:\"engine\",method:\"POST\",path:\"/functions/\"+t,data:e._encode(n,null,!0),authOptions:r}).then(function(t){return e._decode(t).result})},rpc:function(t,n,i){return r.isArray(n)?Promise.reject(new Error(\"Can't pass Array as the param of rpc function in JavaScript SDK.\")):s({service:\"engine\",method:\"POST\",path:\"/call/\"+t,data:e._encodeObjectOrArray(n),authOptions:i}).then(function(t){return e._decode(t).result})},getServerDate:function(){return o(\"date\",null,null,\"GET\").then(function(t){return e._decode(t)})},requestSmsCode:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(r.isString(e)&&(e={mobilePhoneNumber:e}),!e.mobilePhoneNumber)throw new Error(\"Missing mobilePhoneNumber.\");return t.validateToken&&(e=r.extend({},e,{validate_token:t.validateToken})),o(\"requestSmsCode\",null,null,\"POST\",e,t)},verifySmsCode:function(e,t){if(!e)throw new Error(\"Missing sms code.\");var n={};return r.isString(t)&&(n.mobilePhoneNumber=t),o(\"verifySmsCode\",e,null,\"POST\",n)},requestCaptcha:function(e){return o(\"requestCaptcha\",null,null,\"GET\",e).then(function(e){var t=e.captcha_url,n=e.captcha_token;return{captchaToken:n,url:t}})},verifyCaptcha:function(e,t){return o(\"verifyCaptcha\",null,null,\"POST\",{captcha_code:e,captcha_token:t}).then(function(e){var t=e.validate_token;return t})}})}},function(e,t,n){\"use strict\";var r=n(0);e.exports=function(e){var t=/\\s+/,n=Array.prototype.slice;e.Events={on:function(e,n,r){var i,o,s,a,u;if(!n)return this;for(e=e.split(t),i=this._callbacks||(this._callbacks={}),o=e.shift();o;)u=i[o],s=u?u.tail:{},s.next=a={},s.context=r,s.callback=n,i[o]={tail:a,next:u?u.next:s},o=e.shift();return this},off:function(e,n,i){var o,s,a,u,c,l;if(s=this._callbacks){if(!(e||n||i))return delete this._callbacks,this;for(e=e?e.split(t):r.keys(s),o=e.shift();o;)if(a=s[o],delete s[o],a&&(n||i)){for(u=a.tail,a=a.next;a!==u;)c=a.callback,l=a.context,(n&&c!==n||i&&l!==i)&&this.on(o,c,l),a=a.next;o=e.shift()}return this}},trigger:function(e){var r,i,o,s,a,u,c;if(!(o=this._callbacks))return this;for(u=o.all,e=e.split(t),c=n.call(arguments,1),r=e.shift();r;){if(i=o[r])for(s=i.tail;(i=i.next)!==s;)i.callback.apply(i.context||this,c);if(i=u)for(s=i.tail,a=[r].concat(c);(i=i.next)!==s;)i.callback.apply(i.context||this,a);r=e.shift()}return this}},e.Events.bind=e.Events.on,e.Events.unbind=e.Events.off}},function(e,t,n){\"use strict\";var r=n(0),i=n(44),o=n(45),s=n(46),a=n(3),u=n(2)._request,c=n(1),l=n(4),h=l.tap,f=l.transformFetchOptions,d=n(5)(\"leancloud:file\"),p=n(49);e.exports=function(e){var t=(e._config,function(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)}),n=function(e){return e.match(/^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/)[4]},l=function(e){if(e<26)return String.fromCharCode(65+e);if(e<52)return String.fromCharCode(97+(e-26));if(e<62)return String.fromCharCode(48+(e-52));if(62===e)return\"+\";if(63===e)return\"/\";throw new Error(\"Tried to encode large digit \"+e+\" in base64.\")},_=function(e){var t=[];return t.length=Math.ceil(e.length/3),r.times(t.length,function(n){var r=e[3*n],i=e[3*n+1]||0,o=e[3*n+2]||0,s=3*n+1<e.length,a=3*n+2<e.length;t[n]=[l(r>>2&63),l(r<<4&48|i>>4&15),s?l(i<<2&60|o>>6&3):\"=\",a?l(63&o):\"=\"].join(\"\")}),t.join(\"\")};e.File=function(t,n,i){if(this.attributes={name:t,url:\"\",metaData:{},base64:\"\"},r.isString(n))throw new TypeError(\"Creating an AV.File from a String is not yet supported.\");r.isArray(n)&&(this.attributes.metaData.size=n.length,n={base64:_(n)}),this._extName=\"\",this._data=n;var o=void 0;if(n&&n.owner)o=n.owner;else if(!e._config.disableCurrentUser)try{o=e.User.current()}catch(e){if(\"SYNC_API_NOT_AVAILABLE\"!==e.code)throw e;console.warn(\"Get current user failed. It seems this runtime use an async storage system, please create AV.File in the callback of AV.User.currentAsync().\")}this.attributes.metaData.owner=o?o.id:\"unknown\",this.set(\"mime_type\",i)},e.File.withURL=function(t,n,r,i){if(!t||!n)throw new Error(\"Please provide file name and url\");var o=new e.File(t,null,i);if(r)for(var s in r)o.attributes.metaData[s]||(o.attributes.metaData[s]=r[s]);return o.attributes.url=n,o.attributes.metaData.__source=\"external\",o},e.File.createWithoutData=function(t){var n=new e.File;return n.id=t,n},r.extend(e.File.prototype,{className:\"_File\",_toFullJSON:function(t){var n=this,i=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],o=r.clone(this.attributes);return e._objectEach(o,function(n,r){o[r]=e._encode(n,t,void 0,i)}),e._objectEach(this._operations,function(e,t){o[t]=e}),r.has(this,\"id\")&&(o.objectId=this.id),r([\"createdAt\",\"updatedAt\"]).each(function(e){if(r.has(n,e)){var t=n[e];o[e]=r.isDate(t)?t.toJSON():t}}),i&&(o.__type=\"File\"),o},toFullJSON:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return this._toFullJSON(e)},toJSON:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[this];return this._toFullJSON(n,!1)},getACL:function(){return this._acl},setACL:function(t){return t instanceof e.ACL?void(this._acl=t):new a(a.OTHER_CAUSE,\"ACL must be a AV.ACL.\")},name:function(){return this.get(\"name\")},url:function(){return this.get(\"url\")},get:function(e){switch(e){case\"objectId\":return this.id;case\"url\":case\"name\":case\"mime_type\":case\"metaData\":case\"createdAt\":case\"updatedAt\":return this.attributes[e];default:return this.attributes.metaData[e]}},set:function e(){for(var t=this,e=function(e,n){switch(e){case\"name\":case\"url\":case\"mime_type\":case\"base64\":case\"metaData\":t.attributes[e]=n;break;default:t.attributes.metaData[e]=n}},n=arguments.length,r=Array(n),i=0;i<n;i++)r[i]=arguments[i];switch(r.length){case 1:for(var o in r[0])e(o,r[0][o]);break;case 2:e(r[0],r[1])}},metaData:function(e,t){return e&&t?(this.attributes.metaData[e]=t,this):e&&!t?this.attributes.metaData[e]:this.attributes.metaData},thumbnailURL:function(e,t,n,r,i){var o=this.attributes.url;if(!o)throw new Error(\"Invalid url.\");if(!e||!t||e<=0||t<=0)throw new Error(\"Invalid width or height value.\");if(n=n||100,r=!r||r,n<=0||n>100)throw new Error(\"Invalid quality value.\");i=i||\"png\";var s=r?2:1;return o+\"?imageView/\"+s+\"/w/\"+e+\"/h/\"+t+\"/q/\"+n+\"/format/\"+i},size:function(){return this.metaData().size},ownerId:function(){return this.metaData().owner},destroy:function(e){if(!this.id)return c.reject(new Error(\"The file id is not eixsts.\"));var t=u(\"files\",null,this.id,\"DELETE\",null,e);return t},_fileToken:function(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:\"fileTokens\",i=this.attributes.name,o=n(i);!o&&this._extName&&(i+=this._extName,o=this._extName);var s=t()+t()+t()+t()+t()+o,a={key:s,name:i,ACL:this._acl,mime_type:e,metaData:this.attributes.metaData};return this._qiniu_key=s,u(r,null,null,\"POST\",a)},save:function(e){var t=this;if(this.id)throw new Error(\"File already saved. If you want to manipulate a file, use AV.Query to get it.\");if(!this._previousSave)if(this._data){var r=this.get(\"mime_type\");this._previousSave=this._fileToken(r).then(function(a){return a.mime_type&&(r=a.mime_type,t.set(\"mime_type\",r)),t._token=a.token,c.resolve().then(function(){var e=t._data;if(e&&e.base64)return p(e.base64,r);if(e&&e.blob)return!e.blob.type&&r&&(e.blob.type=r),e.blob.name||(e.blob.name=t.get(\"name\")),t._extName=n(e.blob.uri),e.blob;if(\"undefined\"!=typeof File&&e instanceof File)return e.size&&(t.attributes.metaData.size=e.size),e.name&&(t._extName=n(e.name)),e;if(\"undefined\"!=typeof Buffer&&Buffer.isBuffer(e))return t.attributes.metaData.size=e.length,e;throw new TypeError(\"malformed file data\")}).then(function(n){var r=void 0;switch(a.provider){case\"s3\":r=s(a,n,t,e);break;case\"qcloud\":r=i(a,n,t,e);break;case\"qiniu\":default:r=o(a,n,t,e)}return r.then(h(function(){return t._callback(!0)}),function(e){throw t._callback(!1),e})})})}else if(this.attributes.url&&\"external\"===this.attributes.metaData.__source){var a={name:this.attributes.name,ACL:this._acl,metaData:this.attributes.metaData,mime_type:this.mimeType,url:this.attributes.url};this._previousSave=u(\"files\",this.attributes.name,null,\"post\",a).then(function(e){return t.attributes.name=e.name,t.attributes.url=e.url,t.id=e.objectId,e.size&&(t.attributes.metaData.size=e.size),t})}return this._previousSave},_callback:function(e){u(\"fileCallback\",null,null,\"post\",{token:this._token,result:e}).catch(d),delete this._token,delete this._data},fetch:function(e,t){var n=u(\"files\",null,this.id,\"GET\",f(e),t);return n.then(this._finishFetch.bind(this))},_finishFetch:function(t){var n=e.Object.prototype.parse(t);return n.attributes={name:n.name,url:n.url,mime_type:n.mime_type,bucket:n.bucket},n.attributes.metaData=n.metaData||{},n.id=n.objectId,delete n.objectId,delete n.metaData,delete n.url,delete n.name,delete n.mime_type,delete n.bucket,r.extend(this,n),this}})}},function(e,t,n){\"use strict\";var r=n(0);e.exports=function(e){e.GeoPoint=function(t,n){r.isArray(t)?(e.GeoPoint._validate(t[0],t[1]),this.latitude=t[0],this.longitude=t[1]):r.isObject(t)?(e.GeoPoint._validate(t.latitude,t.longitude),this.latitude=t.latitude,this.longitude=t.longitude):r.isNumber(t)&&r.isNumber(n)?(e.GeoPoint._validate(t,n),this.latitude=t,this.longitude=n):(this.latitude=0,this.longitude=0);var i=this;this.__defineGetter__&&this.__defineSetter__&&(this._latitude=this.latitude,this._longitude=this.longitude,this.__defineGetter__(\"latitude\",function(){return i._latitude}),this.__defineGetter__(\"longitude\",function(){return i._longitude}),this.__defineSetter__(\"latitude\",function(t){e.GeoPoint._validate(t,i.longitude),i._latitude=t}),this.__defineSetter__(\"longitude\",function(t){e.GeoPoint._validate(i.latitude,t),i._longitude=t;\n}))},e.GeoPoint._validate=function(e,t){if(e<-90)throw new Error(\"AV.GeoPoint latitude \"+e+\" < -90.0.\");if(e>90)throw new Error(\"AV.GeoPoint latitude \"+e+\" > 90.0.\");if(t<-180)throw new Error(\"AV.GeoPoint longitude \"+t+\" < -180.0.\");if(t>180)throw new Error(\"AV.GeoPoint longitude \"+t+\" > 180.0.\")},e.GeoPoint.current=function(){return new e.Promise(function(t,n){navigator.geolocation.getCurrentPosition(function(n){t(new e.GeoPoint({latitude:n.coords.latitude,longitude:n.coords.longitude}))},n)})},r.extend(e.GeoPoint.prototype,{toJSON:function(){return e.GeoPoint._validate(this.latitude,this.longitude),{__type:\"GeoPoint\",latitude:this.latitude,longitude:this.longitude}},radiansTo:function(e){var t=Math.PI/180,n=this.latitude*t,r=this.longitude*t,i=e.latitude*t,o=e.longitude*t,s=n-i,a=r-o,u=Math.sin(s/2),c=Math.sin(a/2),l=u*u+Math.cos(n)*Math.cos(i)*c*c;return l=Math.min(1,l),2*Math.asin(Math.sqrt(l))},kilometersTo:function(e){return 6371*this.radiansTo(e)},milesTo:function(e){return 3958.8*this.radiansTo(e)}})}},function(e,t,n){\"use strict\";n(22),e.exports=n(23)},function(e,t,n){\"use strict\";function r(e,t){if(\"us\"===t)return h(\"https://us-api.leancloud.cn\");var n=void 0;switch(e.slice(-9)){case\"-9Nh9j0Va\":return h(\"https://e1-api.leancloud.cn\");case\"-MdYXbMMI\":return h(\"https://us-api.leancloud.cn\");default:return n=e.slice(0,8).toLowerCase(),{push:\"https://\"+n+\".push.lncld.net\",stats:\"https://\"+n+\".stats.lncld.net\",engine:\"https://\"+n+\".engine.lncld.net\",api:\"https://\"+n+\".api.lncld.net\"}}}var i=n(6),o=n(26),s=n(4),a=s.isNullOrUndefined,u=n(0),c=u.extend,l=u.isObject,h=function(e){return{push:e,stats:e,engine:e,api:e}},f=!1;i.init=function(e){if(!l(e))return i.init({appId:e,appKey:arguments.length<=1?void 0:arguments[1],masterKey:arguments.length<=2?void 0:arguments[2],region:arguments.length<=3?void 0:arguments[3]});var t=e.appId,n=e.appKey,s=e.masterKey,a=(e.hookKey,e.region),u=void 0===a?\"cn\":a,h=e.serverURLs,d=e.disableCurrentUser,p=void 0!==d&&d,_=e.production;if(i.applicationId)throw new Error(\"SDK is already initialized.\");s&&console.warn(\"MasterKey is not supposed to be used in browser.\"),i._config.applicationId=t,i._config.applicationKey=n,i._config.masterKey=s,\"undefined\"!=typeof _&&(i._config.production=_),\"undefined\"!=typeof p&&(i._config.disableCurrentUser=p),i._appRouter=new o(i);var v=f||\"undefined\"!=typeof h||\"cn\"!==u;i._setServerURLs(c({},r(t,u),i._config.serverURLs,h),v)},i.setProduction=function(e){a(e)?i._config.production=null:i._config.production=e?1:0},i._setServerURLs=function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];\"string\"!=typeof e?c(i._config.serverURLs,e):i._config.serverURLs=h(e),t&&(i._appRouter?i._appRouter.disable():f=!0)},i.setServerURLs=function(e){return i._setServerURLs(e)},i.initialize=i.init;var d=function(e){return Object.defineProperty(i,e,{get:function(){return i._config[e]},set:function(t){i._config[e]=t}})};[\"applicationId\",\"applicationKey\",\"masterKey\",\"hookKey\"].forEach(d)},function(e,t,n){\"use strict\";var r=n(0),i=n(3),o=n(2),s=o.request;e.exports=function(e){e.Insight=e.Insight||{},r.extend(e.Insight,{startJob:function(t,n){if(!t||!t.sql)throw new Error(\"Please provide the sql to run the job.\");var r={jobConfig:t,appId:e.applicationId};return s({path:\"/bigquery/jobs\",method:\"POST\",data:e._encode(r,null,!0),authOptions:n,signKey:!1}).then(function(t){return e._decode(t).id})},on:function(e,t){}}),e.Insight.JobQuery=function(e,t){if(!e)throw new Error(\"Please provide the job id.\");this.id=e,this.className=t,this._skip=0,this._limit=100},r.extend(e.Insight.JobQuery.prototype,{skip:function(e){return this._skip=e,this},limit:function(e){return this._limit=e,this},find:function(t){var n={skip:this._skip,limit:this._limit};return s({path:\"/bigquery/jobs/\"+this.id,method:\"GET\",query:n,authOptions:t,signKey:!1}).then(function(t){return t.error?e.Promise.reject(new i(t.code,t.error)):e.Promise.resolve(t)})}})}},function(e,t,n){\"use strict\";function r(e,t){return e&&e[t]?i.isFunction(e[t])?e[t]():e[t]:null}var i=n(0),o=n(3),s=n(2),a=s._request,u=n(4),c=u.isNullOrUndefined,l=u.ensureArray,h=u.transformFetchOptions,f=[\"objectId\",\"createdAt\",\"updatedAt\"],d=function(e){if(f.indexOf(e)!==-1)throw new Error(\"key[\"+e+\"] is reserved\")};e.exports=function(e){e.Object=function(t,n){if(i.isString(t))return e.Object._create.apply(this,arguments);t=t||{},n&&n.parse&&(t=this.parse(t),t=this._mergeMagicFields(t));var o=r(this,\"defaults\");o&&(t=i.extend({},o,t)),n&&n.collection&&(this.collection=n.collection),this._serverData={},this._opSetQueue=[{}],this._flags={},this.attributes={},this._hashedJSON={},this._escapedAttributes={},this.cid=i.uniqueId(\"c\"),this.changed={},this._silent={},this._pending={},this.set(t,{silent:!0}),this.changed={},this._silent={},this._pending={},this._hasData=!0,this._previousAttributes=i.clone(this.attributes),this.initialize.apply(this,arguments)},e.Object.saveAll=function(t,n){return e.Object._deepSaveAsync(t,null,n)},e.Object.fetchAll=function(t,n){return e.Promise.resolve().then(function(){return a(\"batch\",null,null,\"POST\",{requests:i.map(t,function(e){if(!e.className)throw new Error(\"object must have className to fetch\");if(!e.id)throw new Error(\"object must have id to fetch\");if(e.dirty())throw new Error(\"object is modified but not saved\");return{method:\"GET\",path:\"/1.1/classes/\"+e.className+\"/\"+e.id}})},n)}).then(function(e){return i.forEach(t,function(t,n){if(!e[n].success){var r=new Error(e[n].error.error);throw r.code=e[n].error.code,r}t._finishFetch(t.parse(e[n].success))}),t})},i.extend(e.Object.prototype,e.Events,{_fetchWhenSave:!1,initialize:function(){},fetchWhenSave:function(e){if(console.warn(\"AV.Object#fetchWhenSave is deprecated, use AV.Object#save with options.fetchWhenSave instead.\"),!i.isBoolean(e))throw new Error(\"Expect boolean value for fetchWhenSave\");this._fetchWhenSave=e},getObjectId:function(){return this.id},getCreatedAt:function(){return this.createdAt||this.get(\"createdAt\")},getUpdatedAt:function(){return this.updatedAt||this.get(\"updatedAt\")},toJSON:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return this._toFullJSON(n,!1)},toFullJSON:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return this._toFullJSON(e)},_toFullJSON:function(t){var n=this,r=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],o=i.clone(this.attributes);if(i.isArray(t))var s=t.concat(this);return e._objectEach(o,function(t,n){o[n]=e._encode(t,s,void 0,r)}),e._objectEach(this._operations,function(e,t){o[t]=e}),i.has(this,\"id\")&&(o.objectId=this.id),i([\"createdAt\",\"updatedAt\"]).each(function(e){if(i.has(n,e)){var t=n[e];o[e]=i.isDate(t)?t.toJSON():t}}),r&&(o.__type=\"Object\",i.isArray(t)&&t.length&&(o.__type=\"Pointer\"),o.className=this.className),o},_refreshCache:function(){var t=this;t._refreshingCache||(t._refreshingCache=!0,e._objectEach(this.attributes,function(n,r){n instanceof e.Object?n._refreshCache():i.isObject(n)&&t._resetCacheForKey(r)&&t.set(r,new e.Op.Set(n),{silent:!0})}),delete t._refreshingCache)},dirty:function(e){this._refreshCache();var t=i.last(this._opSetQueue);return e?!!t[e]:!this.id||i.keys(t).length>0},_toPointer:function(){return{__type:\"Pointer\",className:this.className,objectId:this.id}},get:function(e){switch(e){case\"objectId\":return this.id;case\"createdAt\":case\"updatedAt\":return this[e];default:return this.attributes[e]}},relation:function(t){var n=this.get(t);if(n){if(!(n instanceof e.Relation))throw new Error(\"Called relation() on non-relation field \"+t);return n._ensureParentAndKey(this,t),n}return new e.Relation(this,t)},escape:function(e){var t=this._escapedAttributes[e];if(t)return t;var n,r=this.attributes[e];return n=c(r)?\"\":i.escape(r.toString()),this._escapedAttributes[e]=n,n},has:function(e){return!c(this.attributes[e])},_mergeMagicFields:function(t){var n=this,r=[\"objectId\",\"createdAt\",\"updatedAt\"];return e._arrayEach(r,function(r){t[r]&&(\"objectId\"===r?n.id=t[r]:\"createdAt\"!==r&&\"updatedAt\"!==r||i.isDate(t[r])?n[r]=t[r]:n[r]=e._parseDate(t[r]),delete t[r])}),t},_startSave:function(){this._opSetQueue.push({})},_cancelSave:function(){var t=i.first(this._opSetQueue);this._opSetQueue=i.rest(this._opSetQueue);var n=i.first(this._opSetQueue);e._objectEach(t,function(e,r){var i=t[r],o=n[r];i&&o?n[r]=o._mergeWithPrevious(i):i&&(n[r]=i)}),this._saving=this._saving-1},_finishSave:function(t){var n={};e._traverse(this.attributes,function(t){t instanceof e.Object&&t.id&&t._hasData&&(n[t.id]=t)});var r=i.first(this._opSetQueue);this._opSetQueue=i.rest(this._opSetQueue),this._applyOpSet(r,this._serverData),this._mergeMagicFields(t);var o=this;e._objectEach(t,function(t,r){o._serverData[r]=e._decode(t,r);var i=e._traverse(o._serverData[r],function(t){if(t instanceof e.Object&&n[t.id])return n[t.id]});i&&(o._serverData[r]=i)}),this._rebuildAllEstimatedData(),this._saving=this._saving-1},_finishFetch:function(t,n){this._opSetQueue=[{}],this._mergeMagicFields(t);var r=this;e._objectEach(t,function(t,n){r._serverData[n]=e._decode(t,n)}),this._rebuildAllEstimatedData(),this._refreshCache(),this._opSetQueue=[{}],this._hasData=n},_applyOpSet:function(t,n){var r=this;e._objectEach(t,function(t,i){n[i]=t._estimate(n[i],r,i),n[i]===e.Op._UNSET&&delete n[i]})},_resetCacheForKey:function(t){var n=this.attributes[t];if(i.isObject(n)&&!(n instanceof e.Object)&&!(n instanceof e.File)){n=n.toJSON?n.toJSON():n;var r=JSON.stringify(n);if(this._hashedJSON[t]!==r){var o=!!this._hashedJSON[t];return this._hashedJSON[t]=r,o}}return!1},_rebuildEstimatedDataForKey:function(t){var n=this;delete this.attributes[t],this._serverData[t]&&(this.attributes[t]=this._serverData[t]),e._arrayEach(this._opSetQueue,function(r){var i=r[t];i&&(n.attributes[t]=i._estimate(n.attributes[t],n,t),n.attributes[t]===e.Op._UNSET?delete n.attributes[t]:n._resetCacheForKey(t))})},_rebuildAllEstimatedData:function(){var t=this,n=i.clone(this.attributes);this.attributes=i.clone(this._serverData),e._arrayEach(this._opSetQueue,function(n){t._applyOpSet(n,t.attributes),e._objectEach(n,function(e,n){t._resetCacheForKey(n)})}),e._objectEach(n,function(e,n){t.attributes[n]!==e&&t.trigger(\"change:\"+n,t,t.attributes[n],{})}),e._objectEach(this.attributes,function(e,r){i.has(n,r)||t.trigger(\"change:\"+r,t,e,{})})},set:function(t,n,r){var o;if(i.isObject(t)||c(t)?(o=i.mapObject(t,function(t,n){return d(n),e._decode(t,n)}),r=n):(o={},d(t),o[t]=e._decode(n,t)),r=r||{},!o)return this;o instanceof e.Object&&(o=o.attributes),r.unset&&e._objectEach(o,function(t,n){o[n]=new e.Op.Unset});var s=i.clone(o),a=this;e._objectEach(s,function(t,n){t instanceof e.Op&&(s[n]=t._estimate(a.attributes[n],a,n),s[n]===e.Op._UNSET&&delete s[n])}),this._validate(o,r),r.changes={};var u=this._escapedAttributes;this._previousAttributes||{};return e._arrayEach(i.keys(o),function(t){var n=o[t];n instanceof e.Relation&&(n.parent=a),n instanceof e.Op||(n=new e.Op.Set(n));var s=!0;n instanceof e.Op.Set&&i.isEqual(a.attributes[t],n.value)&&(s=!1),s&&(delete u[t],r.silent?a._silent[t]=!0:r.changes[t]=!0);var c=i.last(a._opSetQueue);c[t]=n._mergeWithPrevious(c[t]),a._rebuildEstimatedDataForKey(t),s?(a.changed[t]=a.attributes[t],r.silent||(a._pending[t]=!0)):(delete a.changed[t],delete a._pending[t])}),r.silent||this.change(r),this},unset:function(e,t){return t=t||{},t.unset=!0,this.set(e,null,t)},increment:function(t,n){return(i.isUndefined(n)||i.isNull(n))&&(n=1),this.set(t,new e.Op.Increment(n))},add:function(t,n){return this.set(t,new e.Op.Add(l(n)))},addUnique:function(t,n){return this.set(t,new e.Op.AddUnique(l(n)))},remove:function(t,n){return this.set(t,new e.Op.Remove(l(n)))},op:function(e){return i.last(this._opSetQueue)[e]},clear:function(e){e=e||{},e.unset=!0;var t=i.extend(this.attributes,this._operations);return this.set(t,e)},_getSaveJSON:function(){var t=i.clone(i.first(this._opSetQueue));return e._objectEach(t,function(e,n){t[n]=e.toJSON()}),t},_canBeSerialized:function(){return e.Object._canBeSerializedAsValue(this.attributes)},fetch:function(e,t){var n=this,r=a(\"classes\",this.className,this.id,\"GET\",h(e),t);return r.then(function(e){return n._finishFetch(n.parse(e),!0),n})},save:function(t,n,r){var o,s,u;i.isObject(t)||c(t)?(o=t,u=n):(o={},o[t]=n,u=r),u=i.clone(u)||{},u.wait&&(s=i.clone(this.attributes));var l=i.clone(u)||{};l.wait&&(l.silent=!0),o&&this.set(o,l);var h=this;h._refreshCache();var f=[],d=[];return e.Object._findUnsavedChildren(h.attributes,f,d),f.length+d.length>0?e.Object._deepSaveAsync(this.attributes,h,u).then(function(){return h.save(null,u)}):(this._startSave(),this._saving=(this._saving||0)+1,this._allPreviousSaves=this._allPreviousSaves||e.Promise.resolve(),this._allPreviousSaves=this._allPreviousSaves.catch(function(e){}).then(function(){var e=h.id?\"PUT\":\"POST\",t=h._getSaveJSON(),n={};if((h._fetchWhenSave||u.fetchWhenSave)&&(n.new=\"true\"),u.query){var r;if(\"function\"==typeof u.query.toJSON&&(r=u.query.toJSON(),r&&(n.where=r.where)),!n.where){var c=new Error(\"options.query is not an AV.Query\");throw c}}i.extend(t,h._flags);var f=\"classes\",d=h.className;\"_User\"!==h.className||h.id||(f=\"users\",d=null);var p=u._makeRequest||a,_=p(f,d,h.id,e,t,u,n);return _=_.then(function(e){var t=h.parse(e);return u.wait&&(t=i.extend(o||{},t)),h._finishSave(t),u.wait&&h.set(s,l),h},function(e){throw h._cancelSave(),e})}),this._allPreviousSaves)},destroy:function(e){e=e||{};var t=this,n=function(){t.trigger(\"destroy\",t,t.collection,e)};if(!this.id)return n();e.wait||n();var r=a(\"classes\",this.className,this.id,\"DELETE\",this._flags,e);return r.then(function(){return e.wait&&n(),t})},parse:function(t){var n=i.clone(t);return i([\"createdAt\",\"updatedAt\"]).each(function(t){n[t]&&(n[t]=e._parseDate(n[t]))}),n.updatedAt||(n.updatedAt=n.createdAt),n},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return!this.id},change:function(t){t=t||{};var n=this._changing;this._changing=!0;var r=this;e._objectEach(this._silent,function(e){r._pending[e]=!0});var o=i.extend({},t.changes,this._silent);if(this._silent={},e._objectEach(o,function(e,n){r.trigger(\"change:\"+n,r,r.get(n),t)}),n)return this;for(var s=function(e,t){r._pending[t]||r._silent[t]||delete r.changed[t]};!i.isEmpty(this._pending);)this._pending={},this.trigger(\"change\",this,t),e._objectEach(this.changed,s),r._previousAttributes=i.clone(this.attributes);return this._changing=!1,this},hasChanged:function(e){return arguments.length?this.changed&&i.has(this.changed,e):!i.isEmpty(this.changed)},changedAttributes:function(t){if(!t)return!!this.hasChanged()&&i.clone(this.changed);var n={},r=this._previousAttributes;return e._objectEach(t,function(e,t){i.isEqual(r[t],e)||(n[t]=e)}),n},previous:function(e){return arguments.length&&this._previousAttributes?this._previousAttributes[e]:null},previousAttributes:function(){return i.clone(this._previousAttributes)},isValid:function(){try{this.validate(this.attributes)}catch(e){return!1}return!0},validate:function(t){if(i.has(t,\"ACL\")&&!(t.ACL instanceof e.ACL))throw new o(o.OTHER_CAUSE,\"ACL must be a AV.ACL.\")},_validate:function(e,t){!t.silent&&this.validate&&(e=i.extend({},this.attributes,e),this.validate(e))},getACL:function(){return this.get(\"ACL\")},setACL:function(e,t){return this.set(\"ACL\",e,t)},disableBeforeHook:function(){this.ignoreHook(\"beforeSave\"),this.ignoreHook(\"beforeUpdate\"),this.ignoreHook(\"beforeDelete\")},disableAfterHook:function(){this.ignoreHook(\"afterSave\"),this.ignoreHook(\"afterUpdate\"),this.ignoreHook(\"afterDelete\")},ignoreHook:function(t){i.contains([\"beforeSave\",\"afterSave\",\"beforeUpdate\",\"afterUpdate\",\"beforeDelete\",\"afterDelete\"],t)||console.trace(\"Unsupported hookName: \"+t),e.hookKey||console.trace(\"ignoreHook required hookKey\"),this._flags.__ignore_hooks||(this._flags.__ignore_hooks=[]),this._flags.__ignore_hooks.push(t)}}),e.Object.createWithoutData=function(t,n,r){var i=new e.Object(t);return i.id=n,i._hasData=r,i},e.Object.destroyAll=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!t||0===t.length)return e.Promise.resolve();var r=i.groupBy(t,function(e){return JSON.stringify({className:e.className,flags:e._flags})}),o={requests:i.map(r,function(e){var t=i.map(e,\"id\").join(\",\");return{method:\"DELETE\",path:\"/1.1/classes/\"+e[0].className+\"/\"+t,body:e[0]._flags}})};return a(\"batch\",null,null,\"POST\",o,n)},e.Object._getSubclass=function(t){if(!i.isString(t))throw new Error(\"AV.Object._getSubclass requires a string argument.\");var n=e.Object._classMap[t];return n||(n=e.Object.extend(t),e.Object._classMap[t]=n),n},e.Object._create=function(t,n,r){var i=e.Object._getSubclass(t);return new i(n,r)},e.Object._classMap={},e.Object._extend=e._extend,e.Object.new=function(t,n){return new e.Object(t,n)},e.Object.extend=function(t,n,r){if(!i.isString(t)){if(t&&i.has(t,\"className\"))return e.Object.extend(t.className,t,n);throw new Error(\"AV.Object.extend's first argument should be the className.\")}\"User\"===t&&(t=\"_User\");var o=null;if(i.has(e.Object._classMap,t)){var s=e.Object._classMap[t];if(!n&&!r)return s;o=s._extend(n,r)}else n=n||{},n._className=t,o=this._extend(n,r);return o.extend=function(n){if(i.isString(n)||n&&i.has(n,\"className\"))return e.Object.extend.apply(o,arguments);var r=[t].concat(i.toArray(arguments));return e.Object.extend.apply(o,r)},o.new=function(e,t){return new o(e,t)},e.Object._classMap[t]=o,o},Object.defineProperty(e.Object.prototype,\"className\",{get:function(){var e=this._className||this.constructor._LCClassName||this.constructor.name;return\"User\"===e?\"_User\":e}}),e.Object.register=function(t,n){if(!(t.prototype instanceof e.Object))throw new Error(\"registered class is not a subclass of AV.Object\");var r=n||t.name;if(!r.length)throw new Error(\"registered class must be named\");n&&(t._LCClassName=n),e.Object._classMap[r]=t},e.Object._findUnsavedChildren=function(t,n,r){e._traverse(t,function(t){return t instanceof e.Object?(t._refreshCache(),void(t.dirty()&&n.push(t))):t instanceof e.File?void(t.url()||t.id||r.push(t)):void 0})},e.Object._canBeSerializedAsValue=function(t){var n=!0;return t instanceof e.Object||t instanceof e.File?n=!!t.id:i.isArray(t)?e._arrayEach(t,function(t){e.Object._canBeSerializedAsValue(t)||(n=!1)}):i.isObject(t)&&e._objectEach(t,function(t){e.Object._canBeSerializedAsValue(t)||(n=!1)}),n},e.Object._deepSaveAsync=function(t,n,r){var s=[],u=[];e.Object._findUnsavedChildren(t,s,u),n&&(s=i.filter(s,function(e){return e!=n}));var c=e.Promise.resolve();i.each(u,function(e){c=c.then(function(){return e.save()})});var l=i.uniq(s),h=i.uniq(l);return c.then(function(){return e.Promise._continueWhile(function(){return h.length>0},function(){var t=[],n=[];if(e._arrayEach(h,function(e){return t.length>20?void n.push(e):void(e._canBeSerialized()?t.push(e):n.push(e))}),h=n,0===t.length)return e.Promise.reject(new o(o.OTHER_CAUSE,\"Tried to save a batch with a cycle.\"));var s=e.Promise.resolve(i.map(t,function(t){return t._allPreviousSaves||e.Promise.resolve()})),u=s.then(function(){return a(\"batch\",null,null,\"POST\",{requests:i.map(t,function(e){var t=e._getSaveJSON();i.extend(t,e._flags);var n=\"POST\",r=\"/1.1/classes/\"+e.className;return e.id&&(r=r+\"/\"+e.id,n=\"PUT\"),e._startSave(),{method:n,path:r,body:t}})},r).then(function(n){var r;if(e._arrayEach(t,function(e,t){n[t].success?e._finishSave(e.parse(n[t].success)):(r=r||n[t].error,e._cancelSave())}),r)return e.Promise.reject(new o(r.code,r.error))})});return e._arrayEach(t,function(e){e._allPreviousSaves=u}),u})}).then(function(){return t})}}},function(e,t,n){\"use strict\";var r=n(0);e.exports=function(e){e.Op=function(){this._initialize.apply(this,arguments)},r.extend(e.Op.prototype,{_initialize:function(){}}),r.extend(e.Op,{_extend:e._extend,_opDecoderMap:{},_registerDecoder:function(t,n){e.Op._opDecoderMap[t]=n},_decode:function(t){var n=e.Op._opDecoderMap[t.__op];return n?n(t):void 0}}),e.Op._registerDecoder(\"Batch\",function(t){var n=null;return e._arrayEach(t.ops,function(t){t=e.Op._decode(t),n=t._mergeWithPrevious(n)}),n}),e.Op.Set=e.Op._extend({_initialize:function(e){this._value=e},value:function(){return this._value},toJSON:function(){return e._encode(this.value())},_mergeWithPrevious:function(e){return this},_estimate:function(e){return this.value()}}),e.Op._UNSET={},e.Op.Unset=e.Op._extend({toJSON:function(){return{__op:\"Delete\"}},_mergeWithPrevious:function(e){return this},_estimate:function(t){return e.Op._UNSET}}),e.Op._registerDecoder(\"Delete\",function(t){return new e.Op.Unset}),e.Op.Increment=e.Op._extend({_initialize:function(e){this._amount=e},amount:function(){return this._amount},toJSON:function(){return{__op:\"Increment\",amount:this._amount}},_mergeWithPrevious:function(t){if(t){if(t instanceof e.Op.Unset)return new e.Op.Set(this.amount());if(t instanceof e.Op.Set)return new e.Op.Set(t.value()+this.amount());if(t instanceof e.Op.Increment)return new e.Op.Increment(this.amount()+t.amount());throw new Error(\"Op is invalid after previous op.\")}return this},_estimate:function(e){return e?e+this.amount():this.amount()}}),e.Op._registerDecoder(\"Increment\",function(t){return new e.Op.Increment(t.amount)}),e.Op.Add=e.Op._extend({_initialize:function(e){this._objects=e},objects:function(){return this._objects},toJSON:function(){return{__op:\"Add\",objects:e._encode(this.objects())}},_mergeWithPrevious:function(t){if(t){if(t instanceof e.Op.Unset)return new e.Op.Set(this.objects());if(t instanceof e.Op.Set)return new e.Op.Set(this._estimate(t.value()));if(t instanceof e.Op.Add)return new e.Op.Add(t.objects().concat(this.objects()));throw new Error(\"Op is invalid after previous op.\")}return this},_estimate:function(e){return e?e.concat(this.objects()):r.clone(this.objects())}}),e.Op._registerDecoder(\"Add\",function(t){return new e.Op.Add(e._decode(t.objects))}),e.Op.AddUnique=e.Op._extend({_initialize:function(e){this._objects=r.uniq(e)},objects:function(){return this._objects},toJSON:function(){return{__op:\"AddUnique\",objects:e._encode(this.objects())}},_mergeWithPrevious:function(t){if(t){if(t instanceof e.Op.Unset)return new e.Op.Set(this.objects());if(t instanceof e.Op.Set)return new e.Op.Set(this._estimate(t.value()));if(t instanceof e.Op.AddUnique)return new e.Op.AddUnique(this._estimate(t.objects()));throw new Error(\"Op is invalid after previous op.\")}return this},_estimate:function(t){if(t){var n=r.clone(t);return e._arrayEach(this.objects(),function(t){if(t instanceof e.Object&&t.id){var i=r.find(n,function(n){return n instanceof e.Object&&n.id===t.id});if(i){var o=r.indexOf(n,i);n[o]=t}else n.push(t)}else r.contains(n,t)||n.push(t)}),n}return r.clone(this.objects())}}),e.Op._registerDecoder(\"AddUnique\",function(t){return new e.Op.AddUnique(e._decode(t.objects))}),e.Op.Remove=e.Op._extend({_initialize:function(e){this._objects=r.uniq(e)},objects:function(){return this._objects},toJSON:function(){return{__op:\"Remove\",objects:e._encode(this.objects())}},_mergeWithPrevious:function(t){if(t){if(t instanceof e.Op.Unset)return t;if(t instanceof e.Op.Set)return new e.Op.Set(this._estimate(t.value()));if(t instanceof e.Op.Remove)return new e.Op.Remove(r.union(t.objects(),this.objects()));throw new Error(\"Op is invalid after previous op.\")}return this},_estimate:function(t){if(t){var n=r.difference(t,this.objects());return e._arrayEach(this.objects(),function(t){t instanceof e.Object&&t.id&&(n=r.reject(n,function(n){return n instanceof e.Object&&n.id===t.id}))}),n}return[]}}),e.Op._registerDecoder(\"Remove\",function(t){return new e.Op.Remove(e._decode(t.objects))}),e.Op.Relation=e.Op._extend({_initialize:function(t,n){this._targetClassName=null;var i=this,o=function(t){if(t instanceof e.Object){if(!t.id)throw new Error(\"You can't add an unsaved AV.Object to a relation.\");if(i._targetClassName||(i._targetClassName=t.className),i._targetClassName!==t.className)throw new Error(\"Tried to create a AV.Relation with 2 different types: \"+i._targetClassName+\" and \"+t.className+\".\");return t.id}return t};this.relationsToAdd=r.uniq(r.map(t,o)),this.relationsToRemove=r.uniq(r.map(n,o))},added:function(){var t=this;return r.map(this.relationsToAdd,function(n){var r=e.Object._create(t._targetClassName);return r.id=n,r})},removed:function(){var t=this;return r.map(this.relationsToRemove,function(n){var r=e.Object._create(t._targetClassName);return r.id=n,r})},toJSON:function(){var e=null,t=null,n=this,i=function(e){return{__type:\"Pointer\",className:n._targetClassName,objectId:e}},o=null;return this.relationsToAdd.length>0&&(o=r.map(this.relationsToAdd,i),e={__op:\"AddRelation\",objects:o}),this.relationsToRemove.length>0&&(o=r.map(this.relationsToRemove,i),t={__op:\"RemoveRelation\",objects:o}),e&&t?{__op:\"Batch\",ops:[e,t]}:e||t||{}},_mergeWithPrevious:function(t){if(t){if(t instanceof e.Op.Unset)throw new Error(\"You can't modify a relation after deleting it.\");if(t instanceof e.Op.Relation){if(t._targetClassName&&t._targetClassName!==this._targetClassName)throw new Error(\"Related object must be of class \"+t._targetClassName+\", but \"+this._targetClassName+\" was passed in.\");var n=r.union(r.difference(t.relationsToAdd,this.relationsToRemove),this.relationsToAdd),i=r.union(r.difference(t.relationsToRemove,this.relationsToAdd),this.relationsToRemove),o=new e.Op.Relation(n,i);return o._targetClassName=this._targetClassName,o}throw new Error(\"Op is invalid after previous op.\")}return this},_estimate:function(t,n,r){if(t){if(t instanceof e.Relation){if(this._targetClassName)if(t.targetClassName){if(t.targetClassName!==this._targetClassName)throw new Error(\"Related object must be a \"+t.targetClassName+\", but a \"+this._targetClassName+\" was passed in.\")}else t.targetClassName=this._targetClassName;return t}throw new Error(\"Op is invalid after previous op.\")}var i=new e.Relation(n,r);i.targetClassName=this._targetClassName}}),e.Op._registerDecoder(\"AddRelation\",function(t){return new e.Op.Relation(e._decode(t.objects),[])}),e.Op._registerDecoder(\"RemoveRelation\",function(t){return new e.Op.Relation([],e._decode(t.objects))})}},function(e,t,n){\"use strict\";var r=n(2).request;e.exports=function(e){e.Installation=e.Object.extend(\"_Installation\"),e.Push=e.Push||{},e.Push.send=function(e,t){if(e.where&&(e.where=e.where.toJSON().where),e.where&&e.cql)throw new Error(\"Both where and cql can't be set\");if(e.push_time&&(e.push_time=e.push_time.toJSON()),e.expiration_time&&(e.expiration_time=e.expiration_time.toJSON()),e.expiration_time&&e.expiration_time_interval)throw new Error(\"Both expiration_time and expiration_time_interval can't be set\");return r({service:\"push\",method:\"POST\",path:\"/push\",data:e,authOptions:t})}}},function(e,t,n){\"use strict\";var r=n(0),i=n(5)(\"leancloud:query\"),o=n(1),s=n(3),a=n(2)._request,u=n(4),c=u.ensureArray,l=function(e,t){if(void 0===e)throw new Error(t)};e.exports=function(e){e.Query=function(t){r.isString(t)&&(t=e.Object._getSubclass(t)),this.objectClass=t,this.className=t.prototype.className,this._where={},this._include=[],this._select=[],this._limit=-1,this._skip=0,this._extraOptions={}},e.Query.or=function(){var t=r.toArray(arguments),n=null;e._arrayEach(t,function(e){if(r.isNull(n)&&(n=e.className),n!==e.className)throw new Error(\"All queries must be for the same class\")});var i=new e.Query(n);return i._orQuery(t),i},e.Query.and=function(){var t=r.toArray(arguments),n=null;e._arrayEach(t,function(e){if(r.isNull(n)&&(n=e.className),n!==e.className)throw new Error(\"All queries must be for the same class\")});var i=new e.Query(n);return i._andQuery(t),i},e.Query.doCloudQuery=function(t,n,i){var o={cql:t};r.isArray(n)?o.pvalues=n:i=n;var s=a(\"cloudQuery\",null,null,\"GET\",o,i);return s.then(function(t){var n=new e.Query(t.className),i=r.map(t.results,function(e){var r=n._newObject(t);return r._finishFetch&&r._finishFetch(n._processResult(e),!0),r});return{results:i,count:t.count,className:t.className}})},e.Query._extend=e._extend,r.extend(e.Query.prototype,{_processResult:function(e){return e},get:function(e,t){if(!e){var n=new s(s.OBJECT_NOT_FOUND,\"Object not found.\");throw n}var r=this,i=r._newObject();i.id=e;var o=r.toJSON(),a={};return o.keys&&(a.keys=o.keys),o.include&&(a.include=o.include),o.includeACL&&(a.includeACL=o.includeACL),i.fetch(a,t)},toJSON:function(){var t={where:this._where};return this._include.length>0&&(t.include=this._include.join(\",\")),this._select.length>0&&(t.keys=this._select.join(\",\")),void 0!==this._includeACL&&(t.returnACL=this._includeACL),this._limit>=0&&(t.limit=this._limit),this._skip>0&&(t.skip=this._skip),void 0!==this._order&&(t.order=this._order),e._objectEach(this._extraOptions,function(e,n){t[n]=e}),t},_newObject:function(t){var n;return n=t&&t.className?new e.Object(t.className):new this.objectClass},_createRequest:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.toJSON(),t=arguments[1];if(JSON.stringify(e).length>2e3){var n={requests:[{method:\"GET\",path:\"/1.1/classes/\"+this.className,params:e}]};return a(\"batch\",null,null,\"POST\",n,t).then(function(e){var t=e[0];if(t.success)return t.success;var n=new Error(t.error.error||\"Unknown batch error\");throw n.code=t.error.code,n})}return a(\"classes\",this.className,null,\"GET\",e,t)},_parseResponse:function(e){var t=this;return r.map(e.results,function(n){var r=t._newObject(e);return r._finishFetch&&r._finishFetch(t._processResult(n),!0),r})},find:function(e){var t=this._createRequest(void 0,e);return t.then(this._parseResponse.bind(this))},scan:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.orderedBy,s=t.batchSize,u=arguments[1],c=this.toJSON();i(\"scan %O\",c),c.order&&(console.warn(\"The order of the query is ignored for Query#scan. Checkout the orderedBy option of Query#scan.\"),delete c.order),c.skip&&(console.warn(\"The skip option of the query is ignored for Query#scan.\"),delete c.skip),c.limit&&(console.warn(\"The limit option of the query is ignored for Query#scan.\"),delete c.limit),n&&(c.scan_key=n),s&&(c.limit=s);var l=o.resolve([]),h=void 0,f=!1;return{next:function(){return l=l.then(function(t){return f?[]:t.length>1?t:h||0===t.length?a(\"scan/classes\",e.className,null,\"GET\",h?r.extend({},c,{cursor:h}):c,u).then(function(t){return h=t.cursor,e._parseResponse(t)}).then(function(e){return e.length||(f=!0),t.concat(e)}):(f=!0,t)}),l.then(function(e){return e.shift()}).then(function(e){return{value:e,done:f}})}}},destroyAll:function(t){var n=this;return n.find(t).then(function(n){return e.Object.destroyAll(n,t)})},count:function(e){var t=this.toJSON();t.limit=0,t.count=1;var n=this._createRequest(t,e);return n.then(function(e){return e.count})},first:function(e){var t=this,n=this.toJSON();n.limit=1;var i=this._createRequest(n,e);return i.then(function(e){return r.map(e.results,function(e){var n=t._newObject();return n._finishFetch&&n._finishFetch(t._processResult(e),!0),n})[0]})},skip:function(e){return l(e,\"undefined is not a valid skip value\"),this._skip=e,this},limit:function(e){return l(e,\"undefined is not a valid limit value\"),this._limit=e,this},equalTo:function(t,n){return l(t,\"undefined is not a valid key\"),l(n,\"undefined is not a valid value\"),this._where[t]=e._encode(n),this},_addCondition:function(t,n,r){return l(t,\"undefined is not a valid condition key\"),l(n,\"undefined is not a valid condition\"),l(r,\"undefined is not a valid condition value\"),this._where[t]||(this._where[t]={}),this._where[t][n]=e._encode(r),this},sizeEqualTo:function(e,t){this._addCondition(e,\"$size\",t)},notEqualTo:function(e,t){return this._addCondition(e,\"$ne\",t),this},lessThan:function(e,t){return this._addCondition(e,\"$lt\",t),this},greaterThan:function(e,t){return this._addCondition(e,\"$gt\",t),this},lessThanOrEqualTo:function(e,t){return this._addCondition(e,\"$lte\",t),this},greaterThanOrEqualTo:function(e,t){return this._addCondition(e,\"$gte\",t),this},containedIn:function(e,t){return this._addCondition(e,\"$in\",t),this},notContainedIn:function(e,t){return this._addCondition(e,\"$nin\",t),this},containsAll:function(e,t){\nreturn this._addCondition(e,\"$all\",t),this},exists:function(e){return this._addCondition(e,\"$exists\",!0),this},doesNotExist:function(e){return this._addCondition(e,\"$exists\",!1),this},matches:function(e,t,n){return this._addCondition(e,\"$regex\",t),n||(n=\"\"),t.ignoreCase&&(n+=\"i\"),t.multiline&&(n+=\"m\"),n&&n.length&&this._addCondition(e,\"$options\",n),this},matchesQuery:function(e,t){var n=t.toJSON();return n.className=t.className,this._addCondition(e,\"$inQuery\",n),this},doesNotMatchQuery:function(e,t){var n=t.toJSON();return n.className=t.className,this._addCondition(e,\"$notInQuery\",n),this},matchesKeyInQuery:function(e,t,n){var r=n.toJSON();return r.className=n.className,this._addCondition(e,\"$select\",{key:t,query:r}),this},doesNotMatchKeyInQuery:function(e,t,n){var r=n.toJSON();return r.className=n.className,this._addCondition(e,\"$dontSelect\",{key:t,query:r}),this},_orQuery:function(e){var t=r.map(e,function(e){return e.toJSON().where});return this._where.$or=t,this},_andQuery:function(e){var t=r.map(e,function(e){return e.toJSON().where});return this._where.$and=t,this},_quote:function(e){return\"\\\\Q\"+e.replace(\"\\\\E\",\"\\\\E\\\\\\\\E\\\\Q\")+\"\\\\E\"},contains:function(e,t){return this._addCondition(e,\"$regex\",this._quote(t)),this},startsWith:function(e,t){return this._addCondition(e,\"$regex\",\"^\"+this._quote(t)),this},endsWith:function(e,t){return this._addCondition(e,\"$regex\",this._quote(t)+\"$\"),this},ascending:function(e){return l(e,\"undefined is not a valid key\"),this._order=e,this},addAscending:function(e){return l(e,\"undefined is not a valid key\"),this._order?this._order+=\",\"+e:this._order=e,this},descending:function(e){return l(e,\"undefined is not a valid key\"),this._order=\"-\"+e,this},addDescending:function(e){return l(e,\"undefined is not a valid key\"),this._order?this._order+=\",-\"+e:this._order=\"-\"+e,this},near:function(t,n){return n instanceof e.GeoPoint||(n=new e.GeoPoint(n)),this._addCondition(t,\"$nearSphere\",n),this},withinRadians:function(e,t,n){return this.near(e,t),this._addCondition(e,\"$maxDistance\",n),this},withinMiles:function(e,t,n){return this.withinRadians(e,t,n/3958.8)},withinKilometers:function(e,t,n){return this.withinRadians(e,t,n/6371)},withinGeoBox:function(t,n,r){return n instanceof e.GeoPoint||(n=new e.GeoPoint(n)),r instanceof e.GeoPoint||(r=new e.GeoPoint(r)),this._addCondition(t,\"$within\",{$box:[n,r]}),this},include:function(e){var t=this;return l(e,\"undefined is not a valid key\"),r(arguments).forEach(function(e){t._include=t._include.concat(c(e))}),this},includeACL:function(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return this._includeACL=e,this},select:function(e){var t=this;return l(e,\"undefined is not a valid key\"),r(arguments).forEach(function(e){t._select=t._select.concat(c(e))}),this},each:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(this._order||this._skip||this._limit>=0){var i=new Error(\"Cannot iterate on a query with sort, skip, or limit.\");return e.Promise.reject(i)}var o=new e.Query(this.objectClass);o._limit=n.batchSize||100,o._where=r.clone(this._where),o._include=r.clone(this._include),o.ascending(\"objectId\");var s=!1;return e.Promise._continueWhile(function(){return!s},function(){return o.find(n).then(function(n){var i=e.Promise.resolve();return r.each(n,function(e){i=i.then(function(){return t(e)})}),i.then(function(){n.length>=o._limit?o.greaterThan(\"objectId\",n[n.length-1].id):s=!0})})})}}),e.FriendShipQuery=e.Query._extend({_objectClass:e.User,_newObject:function(){return new e.User},_processResult:function(e){if(e&&e[this._friendshipTag]){var t=e[this._friendshipTag];return\"Pointer\"===t.__type&&\"_User\"===t.className&&(delete t.__type,delete t.className),t}return null}})}},function(e,t,n){\"use strict\";var r=n(0);e.exports=function(e){e.Relation=function(e,t){if(!r.isString(t))throw new TypeError(\"key must be a string\");this.parent=e,this.key=t,this.targetClassName=null},e.Relation.reverseQuery=function(t,n,r){var i=new e.Query(t);return i.equalTo(n,r._toPointer()),i},r.extend(e.Relation.prototype,{_ensureParentAndKey:function(e,t){if(this.parent=this.parent||e,this.key=this.key||t,this.parent!==e)throw new Error(\"Internal Error. Relation retrieved from two different Objects.\");if(this.key!==t)throw new Error(\"Internal Error. Relation retrieved from two different keys.\")},add:function(t){r.isArray(t)||(t=[t]);var n=new e.Op.Relation(t,[]);this.parent.set(this.key,n),this.targetClassName=n._targetClassName},remove:function(t){r.isArray(t)||(t=[t]);var n=new e.Op.Relation([],t);this.parent.set(this.key,n),this.targetClassName=n._targetClassName},toJSON:function(){return{__type:\"Relation\",className:this.targetClassName}},query:function t(){var n,t;return this.targetClassName?(n=e.Object._getSubclass(this.targetClassName),t=new e.Query(n)):(n=e.Object._getSubclass(this.parent.className),t=new e.Query(n),t._extraOptions.redirectClassNameForKey=this.key),t._addCondition(\"$relatedTo\",\"object\",this.parent._toPointer()),t._addCondition(\"$relatedTo\",\"key\",this.key),t}})}},function(e,t,n){\"use strict\";var r=n(0),i=n(3);e.exports=function(e){e.Role=e.Object.extend(\"_Role\",{constructor:function(t,n){if(r.isString(t)?(e.Object.prototype.constructor.call(this,null,null),this.setName(t)):e.Object.prototype.constructor.call(this,t,n),n){if(!(n instanceof e.ACL))throw new TypeError(\"acl must be an instance of AV.ACL\");this.setACL(n)}},getName:function(){return this.get(\"name\")},setName:function(e,t){return this.set(\"name\",e,t)},getUsers:function(){return this.relation(\"users\")},getRoles:function(){return this.relation(\"roles\")},validate:function(t,n){if(\"name\"in t&&t.name!==this.getName()){var o=t.name;if(this.id&&this.id!==t.objectId)return new i(i.OTHER_CAUSE,\"A role's name can only be set before it has been saved.\");if(!r.isString(o))return new i(i.OTHER_CAUSE,\"A role's name must be a String.\");if(!/^[0-9a-zA-Z\\-_ ]+$/.test(o))return new i(i.OTHER_CAUSE,\"A role's name can only contain alphanumeric characters, _, -, and spaces.\")}return!!e.Object.prototype.validate&&e.Object.prototype.validate.call(this,t,n)}})}},function(e,t,n){\"use strict\";var r=n(0),i=n(2)._request;e.exports=function(e){e.SearchSortBuilder=function(){this._sortFields=[]},r.extend(e.SearchSortBuilder.prototype,{_addField:function(e,t,n,r){var i={};return i[e]={order:t||\"asc\",mode:n||\"avg\",missing:\"_\"+(r||\"last\")},this._sortFields.push(i),this},ascending:function(e,t,n){return this._addField(e,\"asc\",t,n)},descending:function(e,t,n){return this._addField(e,\"desc\",t,n)},whereNear:function(e,t,n){n=n||{};var r={},i={lat:t.latitude,lon:t.longitude},o={order:n.order||\"asc\",mode:n.mode||\"avg\",unit:n.unit||\"km\"};return o[e]=i,r._geo_distance=o,this._sortFields.push(r),this},build:function(){return JSON.stringify(e._encode(this._sortFields))}}),e.SearchQuery=e.Query._extend({_sid:null,_hits:0,_queryString:null,_highlights:null,_sortBuilder:null,_createRequest:function(e,t){return i(\"search/select\",null,null,\"GET\",e||this.toJSON(),t)},sid:function(e){return this._sid=e,this},queryString:function(e){return this._queryString=e,this},highlights:function(e){var t;return t=e&&r.isString(e)?arguments:e,this._highlights=t,this},sortBy:function(e){return this._sortBuilder=e,this},hits:function(){return this._hits||(this._hits=0),this._hits},_processResult:function(e){return delete e.className,delete e._app_url,delete e._deeplink,e},hasMore:function(){return!this._hitEnd},reset:function(){this._hitEnd=!1,this._sid=null,this._hits=0},find:function(){var e=this,t=this._createRequest();return t.then(function(t){return t.sid?(e._oldSid=e._sid,e._sid=t.sid):(e._sid=null,e._hitEnd=!0),e._hits=t.hits||0,r.map(t.results,function(n){n.className&&(t.className=n.className);var r=e._newObject(t);return r.appURL=n._app_url,r._finishFetch(e._processResult(n),!0),r})})},toJSON:function(){var t=e.SearchQuery.__super__.toJSON.call(this);if(delete t.where,this.className&&(t.clazz=this.className),this._sid&&(t.sid=this._sid),!this._queryString)throw new Error(\"Please set query string.\");if(t.q=this._queryString,this._highlights&&(t.highlights=this._highlights.join(\",\")),this._sortBuilder&&t.order)throw new Error(\"sort and order can not be set at same time.\");return this._sortBuilder&&(t.sort=this._sortBuilder.build()),t}})}},function(e,t,n){\"use strict\";var r=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},i=n(0),o=n(2)._request;e.exports=function(e){var t=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return e.User.currentAsync().then(function(n){return n||e.User._fetchUserBySessionToken(t.sessionToken)})},n=function(n){return t(n).then(function(t){return e.Object.createWithoutData(\"_User\",t.id)._toPointer()})};e.Status=function(e,t){return this.data={},this.inboxType=\"default\",this.query=null,e&&\"object\"===(\"undefined\"==typeof e?\"undefined\":r(e))?this.data=e:(e&&(this.data.image=e),t&&(this.data.message=t)),this},i.extend(e.Status.prototype,{get:function(e){return this.data[e]},set:function(e,t){return this.data[e]=t,this},destroy:function(t){if(!this.id)return e.Promise.reject(new Error(\"The status id is not exists.\"));var n=o(\"statuses\",null,this.id,\"DELETE\",t);return n},toObject:function(){return this.id?e.Object.createWithoutData(\"_Status\",this.id):null},_getDataJSON:function(){var t=i.clone(this.data);return e._encode(t)},send:function(){var t=this,r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!r.sessionToken&&!e.User.current())throw new Error(\"Please signin an user.\");return this.query?n(r).then(function(e){var n=t.query.toJSON();n.className=t.query.className;var i={};return i.query=n,t.data=t.data||{},t.data.source=t.data.source||e,i.data=t._getDataJSON(),i.inboxType=t.inboxType||\"default\",o(\"statuses\",null,null,\"POST\",i,r)}).then(function(n){return t.id=n.objectId,t.createdAt=e._parseDate(n.createdAt),t}):e.Status.sendStatusToFollowers(this,r)},_finishFetch:function(t){this.id=t.objectId,this.createdAt=e._parseDate(t.createdAt),this.updatedAt=e._parseDate(t.updatedAt),this.messageId=t.messageId,delete t.messageId,delete t.objectId,delete t.createdAt,delete t.updatedAt,this.data=e._decode(t)}}),e.Status.sendStatusToFollowers=function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!r.sessionToken&&!e.User.current())throw new Error(\"Please signin an user.\");return n(r).then(function(n){var i={};i.className=\"_Follower\",i.keys=\"follower\",i.where={user:n};var s={};s.query=i,t.data=t.data||{},t.data.source=t.data.source||n,s.data=t._getDataJSON(),s.inboxType=t.inboxType||\"default\";var a=o(\"statuses\",null,null,\"POST\",s,r);return a.then(function(n){return t.id=n.objectId,t.createdAt=e._parseDate(n.createdAt),t})})},e.Status.sendPrivateStatus=function(t,r){var s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(!s.sessionToken&&!e.User.current())throw new Error(\"Please signin an user.\");if(!r)throw new Error(\"Invalid target user.\");var a=i.isString(r)?r:r.id;if(!a)throw new Error(\"Invalid target user.\");return n(s).then(function(n){var r={};r.className=\"_User\",r.where={objectId:a};var i={};i.query=r,t.data=t.data||{},t.data.source=t.data.source||n,i.data=t._getDataJSON(),i.inboxType=\"private\",t.inboxType=\"private\";var u=o(\"statuses\",null,null,\"POST\",i,s);return u.then(function(n){return t.id=n.objectId,t.createdAt=e._parseDate(n.createdAt),t})})},e.Status.countUnreadStatuses=function(n){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:\"default\",s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(i.isString(r)||(s=r),!s.sessionToken&&null==n&&!e.User.current())throw new Error(\"Please signin an user or pass the owner objectId.\");return t(s).then(function(t){var n={};return n.inboxType=e._encode(r),n.owner=e._encode(t),o(\"subscribe/statuses/count\",null,null,\"GET\",n,s)})},e.Status.resetUnreadCount=function(n){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:\"default\",s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(i.isString(r)||(s=r),!s.sessionToken&&null==n&&!e.User.current())throw new Error(\"Please signin an user or pass the owner objectId.\");return t(s).then(function(t){var n={};return n.inboxType=e._encode(r),n.owner=e._encode(t),o(\"subscribe/statuses/resetUnreadCount\",null,null,\"POST\",n,s)})},e.Status.statusQuery=function(t){var n=new e.Query(\"_Status\");return t&&n.equalTo(\"source\",t),n},e.InboxQuery=e.Query._extend({_objectClass:e.Status,_sinceId:0,_maxId:0,_inboxType:\"default\",_owner:null,_newObject:function(){return new e.Status},_createRequest:function(e,t){return o(\"subscribe/statuses\",null,null,\"GET\",e||this.toJSON(),t)},sinceId:function(e){return this._sinceId=e,this},maxId:function(e){return this._maxId=e,this},owner:function(e){return this._owner=e,this},inboxType:function(e){return this._inboxType=e,this},toJSON:function(){var t=e.InboxQuery.__super__.toJSON.call(this);return t.owner=e._encode(this._owner),t.inboxType=e._encode(this._inboxType),t.sinceId=e._encode(this._sinceId),t.maxId=e._encode(this._maxId),t}}),e.Status.inboxQuery=function(t,n){var r=new e.InboxQuery(e.Status);return t&&(r._owner=t),n&&(r._inboxType=n),r}}},function(e,t,n){\"use strict\";e.exports=[]},function(e,t,n){\"use strict\";var r=n(18),i=[\"Weapp\"].concat(n(42));e.exports=\"LeanCloud-JS-SDK/\"+r+\" (\"+i.join(\"; \")+\")\"},function(e,t,n){\"use strict\";var r=n(7),i=n(5)(\"cos\"),o=n(1);e.exports=function(e,t,n){var s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};n.attributes.url=e.url,n._bucket=e.bucket,n.id=e.objectId;var a=e.upload_url+\"?sign=\"+encodeURIComponent(e.token);return new o(function(e,o){var u=r(\"POST\",a).field(\"fileContent\",t).field(\"op\",\"upload\");s.onprogress&&u.on(\"progress\",s.onprogress),u.end(function(t,r){return r&&i(r.status,r.body,r.text),t?(r&&(t.statusCode=r.status,t.responseText=r.text,t.response=r.body),o(t)):void e(n)})})}},function(e,t,n){\"use strict\";var r=n(7),i=n(1),o=n(5)(\"qiniu\");e.exports=function(e,t,n){var s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};n.attributes.url=e.url,n._bucket=e.bucket,n.id=e.objectId;var a=e.token;return new i(function(e,i){var u=r(\"POST\",\"https://up.qbox.me\").field(\"file\",t).field(\"name\",n.attributes.name).field(\"key\",n._qiniu_key).field(\"token\",a);s.onprogress&&u.on(\"progress\",s.onprogress),u.end(function(t,r){return r&&o(r.status,r.body,r.text),t?(r&&(t.statusCode=r.status,t.responseText=r.text,t.response=r.body),i(t)):void e(n)})})}},function(e,t,n){\"use strict\";var r=n(7);n(1);e.exports=function(e,t,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};return n.attributes.url=e.url,n._bucket=e.bucket,n.id=e.objectId,new Promise(function(o,s){var a=r(\"PUT\",e.upload_url).set(\"Content-Type\",n.get(\"mime_type\")).send(t);i.onprogress&&a.on(\"progress\",i.onprogress),a.end(function(e,t){return e?(t&&(e.statusCode=t.status,e.responseText=t.text,e.response=t.body),s(e)):void o(n)})})}},function(e,t,n){\"use strict\";var r=n(0),i=n(3),o=n(2)._request,s=n(1),a=function(){if(\"undefined\"==typeof wx||\"function\"!=typeof wx.login)throw new Error(\"Weapp Login is only available in Weapp\");return new s(function(e,t){wx.login({success:function(n){var r=n.code,i=n.errMsg;r?e(r):t(new Error(i))}})})};e.exports=function(e){e.User=e.Object.extend(\"_User\",{_isCurrentUser:!1,_mergeMagicFields:function(t){t.sessionToken&&(this._sessionToken=t.sessionToken,delete t.sessionToken),e.User.__super__._mergeMagicFields.call(this,t)},_cleanupAuthData:function(){if(this.isCurrent()){var t=this.get(\"authData\");t&&e._objectEach(this.get(\"authData\"),function(e,n){t[n]||delete t[n]})}},_synchronizeAllAuthData:function(){var t=this.get(\"authData\");if(t){var n=this;e._objectEach(this.get(\"authData\"),function(e,t){n._synchronizeAuthData(t)})}},_synchronizeAuthData:function(t){if(this.isCurrent()){var n;r.isString(t)?(n=t,t=e.User._authProviders[n]):n=t.getAuthType();var i=this.get(\"authData\");if(i&&t){var o=t.restoreAuthentication(i[n]);o||this._unlinkFrom(t)}}},_handleSaveResult:function(t){return t&&!e._config.disableCurrentUser&&(this._isCurrentUser=!0),this._cleanupAuthData(),this._synchronizeAllAuthData(),delete this._serverData.password,this._rebuildEstimatedDataForKey(\"password\"),this._refreshCache(),!t&&!this.isCurrent()||e._config.disableCurrentUser?s.resolve():s.resolve(e.User._saveCurrentUser(this))},_linkWith:function(t,n){var i,o=this;if(r.isString(t)?(i=t,t=e.User._authProviders[t]):i=t.getAuthType(),n){var s=this.get(\"authData\")||{};return s[i]=n,this.save({authData:s}).then(function(e){return e._handleSaveResult(!0).then(function(){return e})})}return t.authenticate().then(function(e){return o._linkWith(t,e)})},linkWithWeapp:function(){var e=this;return a().then(function(t){return e._linkWith(\"lc_weapp\",{code:t})})},_unlinkFrom:function(t){var n=this;return r.isString(t)&&(t=e.User._authProviders[t]),this._linkWith(t,null).then(function(e){return n._synchronizeAuthData(t),e})},_isLinked:function(e){var t;t=r.isString(e)?e:e.getAuthType();var n=this.get(\"authData\")||{};return!!n[t]},logOut:function(){this._logOutWithAll(),this._isCurrentUser=!1},_logOutWithAll:function(){var t=this.get(\"authData\");if(t){var n=this;e._objectEach(this.get(\"authData\"),function(e,t){n._logOutWith(t)})}},_logOutWith:function(t){this.isCurrent()&&(r.isString(t)&&(t=e.User._authProviders[t]),t&&t.deauthenticate&&t.deauthenticate())},signUp:function(e,t){var n,r=e&&e.username||this.get(\"username\");if(!r||\"\"===r)throw n=new i(i.OTHER_CAUSE,\"Cannot sign up user with an empty name.\");var o=e&&e.password||this.get(\"password\");if(!o||\"\"===o)throw n=new i(i.OTHER_CAUSE,\"Cannot sign up user with an empty password.\");return this.save(e,t).then(function(e){return e._handleSaveResult(!0).then(function(){return e})})},signUpOrlogInWithMobilePhone:function(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=e&&e.mobilePhoneNumber||this.get(\"mobilePhoneNumber\");if(!r||\"\"===r)throw t=new i(i.OTHER_CAUSE,\"Cannot sign up or login user by mobilePhoneNumber with an empty mobilePhoneNumber.\");var s=e&&e.smsCode||this.get(\"smsCode\");if(!s||\"\"===s)throw t=new i(i.OTHER_CAUSE,\"Cannot sign up or login user by mobilePhoneNumber  with an empty smsCode.\");return n._makeRequest=function(e,t,n,r,i){return o(\"usersByMobilePhone\",null,null,\"POST\",i)},this.save(e,n).then(function(e){return delete e.attributes.smsCode,delete e._serverData.smsCode,e._handleSaveResult(!0).then(function(){return e})})},logIn:function(){var e=this,t=o(\"login\",null,null,\"POST\",this.toJSON());return t.then(function(t){var n=e.parse(t);return e._finishFetch(n),e._handleSaveResult(!0).then(function(){return n.smsCode||delete e.attributes.smsCode,e})})},save:function(t,n,i){var o,s;return r.isObject(t)||r.isNull(t)||r.isUndefined(t)?(o=t,s=n):(o={},o[t]=n,s=i),s=s||{},e.Object.prototype.save.call(this,o,s).then(function(e){return e._handleSaveResult(!1).then(function(){return e})})},follow:function(e,t){if(!this.id)throw new Error(\"Please signin.\");if(!e)throw new Error(\"Invalid target user.\");var n=r.isString(e)?e:e.id;if(!n)throw new Error(\"Invalid target user.\");var i=\"users/\"+this.id+\"/friendship/\"+n,s=o(i,null,null,\"POST\",null,t);return s},unfollow:function(e,t){if(!this.id)throw new Error(\"Please signin.\");if(!e)throw new Error(\"Invalid target user.\");var n=r.isString(e)?e:e.id;if(!n)throw new Error(\"Invalid target user.\");var i=\"users/\"+this.id+\"/friendship/\"+n,s=o(i,null,null,\"DELETE\",null,t);return s},followerQuery:function(){return e.User.followerQuery(this.id)},followeeQuery:function(){return e.User.followeeQuery(this.id)},fetch:function(t,n){return e.Object.prototype.fetch.call(this,t,n).then(function(e){return e._handleSaveResult(!1).then(function(){return e})})},updatePassword:function(e,t,n){var r=\"users/\"+this.id+\"/updatePassword\",i={old_password:e,new_password:t},s=o(r,null,null,\"PUT\",i,n);return s},isCurrent:function(){return this._isCurrentUser},getUsername:function(){return this.get(\"username\")},getMobilePhoneNumber:function(){return this.get(\"mobilePhoneNumber\")},setMobilePhoneNumber:function(e,t){return this.set(\"mobilePhoneNumber\",e,t)},setUsername:function(e,t){return this.set(\"username\",e,t)},setPassword:function(e,t){return this.set(\"password\",e,t)},getEmail:function(){return this.get(\"email\")},setEmail:function(e,t){return this.set(\"email\",e,t)},authenticated:function(){return console.warn(\"DEPRECATED: 如果要判断当前用户的登录状态是否有效，请使用 currentUser.isAuthenticated().then()，如果要判断该用户是否是当前登录用户，请使用 user.id === currentUser.id。\"),!!this._sessionToken&&!e._config.disableCurrentUser&&e.User.current()&&e.User.current().id===this.id},isAuthenticated:function(){var t=this;return s.resolve().then(function(){return!!t._sessionToken&&e.User._fetchUserBySessionToken(t._sessionToken).then(function(){return!0},function(e){if(211===e.code)return!1;throw e})})},getSessionToken:function(){return this._sessionToken},refreshSessionToken:function(e){var t=this;return o(\"users/\"+this.id+\"/refreshSessionToken\",null,null,\"PUT\",null,e).then(function(e){return t._finishFetch(e),t._handleSaveResult(!0).then(function(){return t})})},getRoles:function(t){return e.Relation.reverseQuery(\"_Role\",\"users\",this).find(t)}},{_currentUser:null,_currentUserMatchesDisk:!1,_CURRENT_USER_KEY:\"currentUser\",_authProviders:{},signUp:function(t,n,r,i){r=r||{},r.username=t,r.password=n;var o=e.Object._create(\"_User\");return o.signUp(r,i)},logIn:function(t,n,r){var i=e.Object._create(\"_User\");return i._finishFetch({username:t,password:n}),i.logIn(r)},become:function(e){return this._fetchUserBySessionToken(e).then(function(e){return e._handleSaveResult(!0).then(function(){return e})})},_fetchUserBySessionToken:function(t){var n=e.Object._create(\"_User\");return o(\"users\",\"me\",null,\"GET\",{session_token:t}).then(function(e){var t=n.parse(e);return n._finishFetch(t),n})},logInWithMobilePhoneSmsCode:function(t,n,r){var i=e.Object._create(\"_User\");return i._finishFetch({mobilePhoneNumber:t,smsCode:n}),i.logIn(r)},signUpOrlogInWithMobilePhone:function(t,n,r,i){r=r||{},r.mobilePhoneNumber=t,r.smsCode=n;var o=e.Object._create(\"_User\");return o.signUpOrlogInWithMobilePhone(r,i)},logInWithMobilePhone:function(t,n,r){var i=e.Object._create(\"_User\");return i._finishFetch({mobilePhoneNumber:t,password:n}),i.logIn(r)},signUpOrlogInWithAuthData:function(t,n){return e.User._logInWith(n,t)},loginWithWeapp:function(){var e=this;return a().then(function(t){return e.signUpOrlogInWithAuthData({code:t},\"lc_weapp\")})},associateWithAuthData:function(e,t,n){return e._linkWith(t,n)},logOut:function(){return e._config.disableCurrentUser?(console.warn(\"AV.User.current() was disabled in multi-user environment, call logOut() from user object instead https://leancloud.cn/docs/leanengine-node-sdk-upgrade-1.html\"),s.resolve(null)):(null!==e.User._currentUser&&(e.User._currentUser._logOutWithAll(),e.User._currentUser._isCurrentUser=!1),e.User._currentUserMatchesDisk=!0,e.User._currentUser=null,e.localStorage.removeItemAsync(e._getAVPath(e.User._CURRENT_USER_KEY)))},followerQuery:function(t){if(!t||!r.isString(t))throw new Error(\"Invalid user object id.\");var n=new e.FriendShipQuery(\"_Follower\");return n._friendshipTag=\"follower\",n.equalTo(\"user\",e.Object.createWithoutData(\"_User\",t)),n},followeeQuery:function(t){if(!t||!r.isString(t))throw new Error(\"Invalid user object id.\");var n=new e.FriendShipQuery(\"_Followee\");return n._friendshipTag=\"followee\",n.equalTo(\"user\",e.Object.createWithoutData(\"_User\",t)),n},requestPasswordReset:function(e){var t={email:e},n=o(\"requestPasswordReset\",null,null,\"POST\",t);return n},requestEmailVerify:function(e){var t={email:e},n=o(\"requestEmailVerify\",null,null,\"POST\",t);return n},requestMobilePhoneVerify:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n={mobilePhoneNumber:e};t.validateToken&&(n.validate_token=t.validateToken);var r=o(\"requestMobilePhoneVerify\",null,null,\"POST\",n,t);return r},requestPasswordResetBySmsCode:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n={mobilePhoneNumber:e};t.validateToken&&(n.validate_token=t.validateToken);var r=o(\"requestPasswordResetBySmsCode\",null,null,\"POST\",n,t);return r},resetPasswordBySmsCode:function(e,t){var n={password:t},r=o(\"resetPasswordBySmsCode\",null,e,\"PUT\",n);return r},verifyMobilePhone:function(e){var t=o(\"verifyMobilePhone\",null,e,\"POST\",null);return t},requestLoginSmsCode:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n={mobilePhoneNumber:e};t.validateToken&&(n.validate_token=t.validateToken);var r=o(\"requestLoginSmsCode\",null,null,\"POST\",n,t);return r},currentAsync:function(){return e._config.disableCurrentUser?(console.warn(\"AV.User.currentAsync() was disabled in multi-user environment, access user from request instead https://leancloud.cn/docs/leanengine-node-sdk-upgrade-1.html\"),s.resolve(null)):e.User._currentUser?s.resolve(e.User._currentUser):e.User._currentUserMatchesDisk?s.resolve(e.User._currentUser):e.localStorage.getItemAsync(e._getAVPath(e.User._CURRENT_USER_KEY)).then(function(t){if(!t)return null;e.User._currentUserMatchesDisk=!0,e.User._currentUser=e.Object._create(\"_User\"),e.User._currentUser._isCurrentUser=!0;var n=JSON.parse(t);return e.User._currentUser.id=n._id,delete n._id,e.User._currentUser._sessionToken=n._sessionToken,delete n._sessionToken,e.User._currentUser._finishFetch(n),e.User._currentUser._synchronizeAllAuthData(),e.User._currentUser._refreshCache(),e.User._currentUser._opSetQueue=[{}],e.User._currentUser})},current:function(){if(e._config.disableCurrentUser)return console.warn(\"AV.User.current() was disabled in multi-user environment, access user from request instead https://leancloud.cn/docs/leanengine-node-sdk-upgrade-1.html\"),null;if(e.User._currentUser)return e.User._currentUser;if(e.User._currentUserMatchesDisk)return e.User._currentUser;e.User._currentUserMatchesDisk=!0;var t=e.localStorage.getItem(e._getAVPath(e.User._CURRENT_USER_KEY));if(!t)return null;e.User._currentUser=e.Object._create(\"_User\"),e.User._currentUser._isCurrentUser=!0;var n=JSON.parse(t);return e.User._currentUser.id=n._id,delete n._id,e.User._currentUser._sessionToken=n._sessionToken,delete n._sessionToken,e.User._currentUser._finishFetch(n),e.User._currentUser._synchronizeAllAuthData(),e.User._currentUser._refreshCache(),e.User._currentUser._opSetQueue=[{}],e.User._currentUser},_saveCurrentUser:function(t){var n;return n=e.User._currentUser!==t?e.User.logOut():s.resolve(),n.then(function(){t._isCurrentUser=!0,e.User._currentUser=t;var n=t.toJSON();return n._id=t.id,n._sessionToken=t._sessionToken,e.localStorage.setItemAsync(e._getAVPath(e.User._CURRENT_USER_KEY),JSON.stringify(n)).then(function(){e.User._currentUserMatchesDisk=!0})})},_registerAuthenticationProvider:function(t){e.User._authProviders[t.getAuthType()]=t,!e._config.disableCurrentUser&&e.User.current()&&e.User.current()._synchronizeAuthData(t.getAuthType())},_logInWith:function(t,n){var r=e.Object._create(\"_User\");return r._linkWith(t,n)}})}},function(e,t,n){\"use strict\";(function(t){var r=n(0),i=(n(1),{}),o=[\"getItem\",\"setItem\",\"removeItem\",\"clear\"],s=t.localStorage;try{var a=\"__storejs__\";if(s.setItem(a,a),s.getItem(a)!=a)throw new Error;s.removeItem(a)}catch(e){s=n(57)}r(o).each(function(e){i[e]=function(){return s[e].apply(s,arguments)}}),i.async=!1,e.exports=i}).call(t,n(8))},function(e,t,n){\"use strict\";var r=function(e,t){var n;e.indexOf(\"base64\")<0?n=atob(e):e.split(\",\")[0].indexOf(\"base64\")>=0?(t=t||e.split(\",\")[0].split(\":\")[1].split(\";\")[0],n=atob(e.split(\",\")[1])):n=unescape(e.split(\",\")[1]);for(var r=new Uint8Array(n.length),i=0;i<n.length;i++)r[i]=n.charCodeAt(i);return new Blob([r],{type:t})};e.exports=r},function(e,t,n){function r(e){if(e)return i(e)}function i(e){for(var t in r.prototype)e[t]=r.prototype[t];return e}e.exports=r,r.prototype.on=r.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks[\"$\"+e]=this._callbacks[\"$\"+e]||[]).push(t),this},r.prototype.once=function(e,t){function n(){this.off(e,n),t.apply(this,arguments)}return n.fn=t,this.on(e,n),this},r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n=this._callbacks[\"$\"+e];if(!n)return this;if(1==arguments.length)return delete this._callbacks[\"$\"+e],this;for(var r,i=0;i<n.length;i++)if(r=n[i],r===t||r.fn===t){n.splice(i,1);break}return this},r.prototype.emit=function(e){this._callbacks=this._callbacks||{};var t=[].slice.call(arguments,1),n=this._callbacks[\"$\"+e];if(n){n=n.slice(0);for(var r=0,i=n.length;r<i;++r)n[r].apply(this,t)}return this},r.prototype.listeners=function(e){return this._callbacks=this._callbacks||{},this._callbacks[\"$\"+e]||[]},r.prototype.hasListeners=function(e){return!!this.listeners(e).length}},function(e,t){!function(){var t=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\",n={rotl:function(e,t){return e<<t|e>>>32-t},rotr:function(e,t){return e<<32-t|e>>>t},endian:function(e){if(e.constructor==Number)return 16711935&n.rotl(e,8)|4278255360&n.rotl(e,24);for(var t=0;t<e.length;t++)e[t]=n.endian(e[t]);return e},randomBytes:function(e){for(var t=[];e>0;e--)t.push(Math.floor(256*Math.random()));return t},bytesToWords:function(e){for(var t=[],n=0,r=0;n<e.length;n++,r+=8)t[r>>>5]|=e[n]<<24-r%32;return t},wordsToBytes:function(e){for(var t=[],n=0;n<32*e.length;n+=8)t.push(e[n>>>5]>>>24-n%32&255);return t},bytesToHex:function(e){for(var t=[],n=0;n<e.length;n++)t.push((e[n]>>>4).toString(16)),t.push((15&e[n]).toString(16));return t.join(\"\")},hexToBytes:function(e){for(var t=[],n=0;n<e.length;n+=2)t.push(parseInt(e.substr(n,2),16));return t},bytesToBase64:function(e){for(var n=[],r=0;r<e.length;r+=3)for(var i=e[r]<<16|e[r+1]<<8|e[r+2],o=0;o<4;o++)8*r+6*o<=8*e.length?n.push(t.charAt(i>>>6*(3-o)&63)):n.push(\"=\");return n.join(\"\")},base64ToBytes:function(e){e=e.replace(/[^A-Z0-9+\\/]/gi,\"\");for(var n=[],r=0,i=0;r<e.length;i=++r%4)0!=i&&n.push((t.indexOf(e.charAt(r-1))&Math.pow(2,-2*i+8)-1)<<2*i|t.indexOf(e.charAt(r))>>>6-2*i);return n}};e.exports=n}()},function(e,t,n){function r(e){var n,r=0;for(n in e)r=(r<<5)-r+e.charCodeAt(n),r|=0;return t.colors[Math.abs(r)%t.colors.length]}function i(e){function n(){if(n.enabled){var e=n,r=+new Date,i=r-(c||r);e.diff=i,e.prev=c,e.curr=r,c=r;for(var o=new Array(arguments.length),s=0;s<o.length;s++)o[s]=arguments[s];o[0]=t.coerce(o[0]),\"string\"!=typeof o[0]&&o.unshift(\"%O\");var a=0;o[0]=o[0].replace(/%([a-zA-Z%])/g,function(n,r){if(\"%%\"===n)return n;a++;var i=t.formatters[r];if(\"function\"==typeof i){var s=o[a];n=i.call(e,s),o.splice(a,1),a--}return n}),t.formatArgs.call(e,o);var u=n.log||t.log||console.log.bind(console);u.apply(e,o)}}return n.namespace=e,n.enabled=t.enabled(e),n.useColors=t.useColors(),n.color=r(e),\"function\"==typeof t.init&&t.init(n),n}function o(e){t.save(e),t.names=[],t.skips=[];for(var n=(\"string\"==typeof e?e:\"\").split(/[\\s,]+/),r=n.length,i=0;i<r;i++)n[i]&&(e=n[i].replace(/\\*/g,\".*?\"),\"-\"===e[0]?t.skips.push(new RegExp(\"^\"+e.substr(1)+\"$\")):t.names.push(new RegExp(\"^\"+e+\"$\")))}function s(){t.enable(\"\")}function a(e){var n,r;for(n=0,r=t.skips.length;n<r;n++)if(t.skips[n].test(e))return!1;for(n=0,r=t.names.length;n<r;n++)if(t.names[n].test(e))return!0;return!1}function u(e){return e instanceof Error?e.stack||e.message:e}t=e.exports=i.debug=i.default=i,t.coerce=u,t.disable=s,t.enable=o,t.enabled=a,t.humanize=n(59),t.names=[],t.skips=[],t.formatters={};var c},function(e,t,n){(function(t){!function(t,n){e.exports=n()}(this,function(){\"use strict\";function e(e){return\"function\"==typeof e||\"object\"==typeof e&&null!==e}function r(e){return\"function\"==typeof e}function i(e){z=e}function o(e){H=e}function s(){return function(){return process.nextTick(h)}}function a(){return\"undefined\"!=typeof G?function(){\nG(h)}:l()}function u(){var e=0,t=new Y(h),n=document.createTextNode(\"\");return t.observe(n,{characterData:!0}),function(){n.data=e=++e%2}}function c(){var e=new MessageChannel;return e.port1.onmessage=h,function(){return e.port2.postMessage(0)}}function l(){var e=setTimeout;return function(){return e(h,1)}}function h(){for(var e=0;e<K;e+=2){var t=te[e],n=te[e+1];t(n),te[e]=void 0,te[e+1]=void 0}K=0}function f(){try{var e=n(65);return G=e.runOnLoop||e.runOnContext,a()}catch(e){return l()}}function d(e,t){var n=arguments,r=this,i=new this.constructor(_);void 0===i[re]&&R(i);var o=r._state;return o?!function(){var e=n[o-1];H(function(){return k(o,i,e,r._result)})}():j(r,i,e,t),i}function p(e){var t=this;if(e&&\"object\"==typeof e&&e.constructor===t)return e;var n=new t(_);return S(n,e),n}function _(){}function v(){return new TypeError(\"You cannot resolve a promise with itself\")}function y(){return new TypeError(\"A promises callback cannot return that same promise.\")}function m(e){try{return e.then}catch(e){return ae.error=e,ae}}function g(e,t,n,r){try{e.call(t,n,r)}catch(e){return e}}function b(e,t,n){H(function(e){var r=!1,i=g(n,t,function(n){r||(r=!0,t!==n?S(e,n):A(e,n))},function(t){r||(r=!0,T(e,t))},\"Settle: \"+(e._label||\" unknown promise\"));!r&&i&&(r=!0,T(e,i))},e)}function w(e,t){t._state===oe?A(e,t._result):t._state===se?T(e,t._result):j(t,void 0,function(t){return S(e,t)},function(t){return T(e,t)})}function O(e,t,n){t.constructor===e.constructor&&n===d&&t.constructor.resolve===p?w(e,t):n===ae?(T(e,ae.error),ae.error=null):void 0===n?A(e,t):r(n)?b(e,t,n):A(e,t)}function S(t,n){t===n?T(t,v()):e(n)?O(t,n,m(n)):A(t,n)}function E(e){e._onerror&&e._onerror(e._result),N(e)}function A(e,t){e._state===ie&&(e._result=t,e._state=oe,0!==e._subscribers.length&&H(N,e))}function T(e,t){e._state===ie&&(e._state=se,e._result=t,H(E,e))}function j(e,t,n,r){var i=e._subscribers,o=i.length;e._onerror=null,i[o]=t,i[o+oe]=n,i[o+se]=r,0===o&&e._state&&H(N,e)}function N(e){var t=e._subscribers,n=e._state;if(0!==t.length){for(var r=void 0,i=void 0,o=e._result,s=0;s<t.length;s+=3)r=t[s],i=t[s+n],r?k(n,r,i,o):i(o);e._subscribers.length=0}}function x(){this.error=null}function C(e,t){try{return e(t)}catch(e){return ue.error=e,ue}}function k(e,t,n,i){var o=r(n),s=void 0,a=void 0,u=void 0,c=void 0;if(o){if(s=C(n,i),s===ue?(c=!0,a=s.error,s.error=null):u=!0,t===s)return void T(t,y())}else s=i,u=!0;t._state!==ie||(o&&u?S(t,s):c?T(t,a):e===oe?A(t,s):e===se&&T(t,s))}function U(e,t){try{t(function(t){S(e,t)},function(t){T(e,t)})}catch(t){T(e,t)}}function I(){return ce++}function R(e){e[re]=ce++,e._state=void 0,e._result=void 0,e._subscribers=[]}function P(e,t){this._instanceConstructor=e,this.promise=new e(_),this.promise[re]||R(this.promise),Q(t)?(this._input=t,this.length=t.length,this._remaining=t.length,this._result=new Array(this.length),0===this.length?A(this.promise,this._result):(this.length=this.length||0,this._enumerate(),0===this._remaining&&A(this.promise,this._result))):T(this.promise,D())}function D(){return new Error(\"Array Methods must be provided an Array\")}function L(e){return new P(this,e).promise}function q(e){var t=this;return new t(Q(e)?function(n,r){for(var i=e.length,o=0;o<i;o++)t.resolve(e[o]).then(n,r)}:function(e,t){return t(new TypeError(\"You must pass an array to race.\"))})}function M(e){var t=this,n=new t(_);return T(n,e),n}function F(){throw new TypeError(\"You must pass a resolver function as the first argument to the promise constructor\")}function J(){throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\")}function B(e){this[re]=I(),this._result=this._state=void 0,this._subscribers=[],_!==e&&(\"function\"!=typeof e&&F(),this instanceof B?U(this,e):J())}function W(){var e=void 0;if(\"undefined\"!=typeof t)e=t;else if(\"undefined\"!=typeof self)e=self;else try{e=Function(\"return this\")()}catch(e){throw new Error(\"polyfill failed because global object is unavailable in this environment\")}var n=e.Promise;if(n){var r=null;try{r=Object.prototype.toString.call(n.resolve())}catch(e){}if(\"[object Promise]\"===r&&!n.cast)return}e.Promise=B}var V=void 0;V=Array.isArray?Array.isArray:function(e){return\"[object Array]\"===Object.prototype.toString.call(e)};var Q=V,K=0,G=void 0,z=void 0,H=function(e,t){te[K]=e,te[K+1]=t,K+=2,2===K&&(z?z(h):ne())},$=\"undefined\"!=typeof window?window:void 0,X=$||{},Y=X.MutationObserver||X.WebKitMutationObserver,Z=\"undefined\"==typeof self&&\"undefined\"!=typeof process&&\"[object process]\"==={}.toString.call(process),ee=\"undefined\"!=typeof Uint8ClampedArray&&\"undefined\"!=typeof importScripts&&\"undefined\"!=typeof MessageChannel,te=new Array(1e3),ne=void 0;ne=Z?s():Y?u():ee?c():void 0===$?f():l();var re=Math.random().toString(36).substring(16),ie=void 0,oe=1,se=2,ae=new x,ue=new x,ce=0;return P.prototype._enumerate=function(){for(var e=this.length,t=this._input,n=0;this._state===ie&&n<e;n++)this._eachEntry(t[n],n)},P.prototype._eachEntry=function(e,t){var n=this._instanceConstructor,r=n.resolve;if(r===p){var i=m(e);if(i===d&&e._state!==ie)this._settledAt(e._state,t,e._result);else if(\"function\"!=typeof i)this._remaining--,this._result[t]=e;else if(n===B){var o=new n(_);O(o,e,i),this._willSettleAt(o,t)}else this._willSettleAt(new n(function(t){return t(e)}),t)}else this._willSettleAt(r(e),t)},P.prototype._settledAt=function(e,t,n){var r=this.promise;r._state===ie&&(this._remaining--,e===se?T(r,n):this._result[t]=n),0===this._remaining&&A(r,this._result)},P.prototype._willSettleAt=function(e,t){var n=this;j(e,void 0,function(e){return n._settledAt(oe,t,e)},function(e){return n._settledAt(se,t,e)})},B.all=L,B.race=q,B.resolve=p,B.reject=M,B._setScheduler=i,B._setAsap=o,B._asap=H,B.prototype={constructor:B,then:d,catch:function(e){return this.then(null,e)}},B.polyfill=W,B.Promise=B,B})}).call(t,n(8))},function(e,t,n){\"use strict\";function r(e,t){for(var n=e[s][t];null!=n;){if(n.kind===a)return n.listener;n=n.next}return null}function i(e,t,n){\"function\"!=typeof n&&\"object\"!=typeof n&&(n=null);for(var r=null,i=e[s][t];null!=i;)i.kind===a?null==r?e[s][t]=i.next:r.next=i.next:r=i,i=i.next;null!=n&&(null==r?e[s][t]=u(n,a):r.next=u(n,a))}var o=n(10),s=o.LISTENERS,a=o.ATTRIBUTE,u=o.newNode;t.defineCustomEventTarget=function(e,t){function n(){e.call(this)}var o={constructor:{value:n,configurable:!0,writable:!0}};return t.forEach(function(e){o[\"on\"+e]={get:function(){return r(this,e)},set:function(t){i(this,e,t)},configurable:!0,enumerable:!0}}),n.prototype=Object.create(e.prototype,o),n}},function(e,t,n){\"use strict\";var r=n(10).createUniqueKey,i=r(\"stop_immediate_propagation_flag\"),o=r(\"canceled_flag\"),s=r(\"original_event\"),a=Object.freeze({stopPropagation:Object.freeze({value:function(){var e=this[s];\"function\"==typeof e.stopPropagation&&e.stopPropagation()},writable:!0,configurable:!0}),stopImmediatePropagation:Object.freeze({value:function(){this[i]=!0;var e=this[s];\"function\"==typeof e.stopImmediatePropagation&&e.stopImmediatePropagation()},writable:!0,configurable:!0}),preventDefault:Object.freeze({value:function(){this.cancelable===!0&&(this[o]=!0);var e=this[s];\"function\"==typeof e.preventDefault&&e.preventDefault()},writable:!0,configurable:!0}),defaultPrevented:Object.freeze({get:function(){return this[o]},enumerable:!0,configurable:!0})});t.STOP_IMMEDIATE_PROPAGATION_FLAG=i,t.createEventWrapper=function(e,t){var n=\"number\"==typeof e.timeStamp?e.timeStamp:Date.now(),r={type:{value:e.type,enumerable:!0},target:{value:t,enumerable:!0},currentTarget:{value:t,enumerable:!0},eventPhase:{value:2,enumerable:!0},bubbles:{value:Boolean(e.bubbles),enumerable:!0},cancelable:{value:Boolean(e.cancelable),enumerable:!0},timeStamp:{value:n,enumerable:!0},isTrusted:{value:!1,enumerable:!0}};return r[i]={value:!1,writable:!0},r[o]={value:!1,writable:!0},r[s]={value:e},\"undefined\"!=typeof e.detail&&(r.detail={value:e.detail,enumerable:!0}),Object.create(Object.create(e,a),r)}},function(e,t){function n(e){return!!e.constructor&&\"function\"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function r(e){return\"function\"==typeof e.readFloatLE&&\"function\"==typeof e.slice&&n(e.slice(0,0))}e.exports=function(e){return null!=e&&(n(e)||r(e)||!!e._isBuffer)}},function(e,t,n){!function(t){var n={},r={};n.length=0,n.getItem=function(e){return r[e]||null},n.setItem=function(e,t){\"undefined\"==typeof t?n.removeItem(e):(r.hasOwnProperty(e)||n.length++,r[e]=\"\"+t)},n.removeItem=function(e){r.hasOwnProperty(e)&&(delete r[e],n.length--)},n.key=function(e){return Object.keys(r)[e]||null},n.clear=function(){r={},n.length=0},e.exports=n}(this)},function(e,t,n){!function(){var t=n(51),r=n(19).utf8,i=n(56),o=n(19).bin,s=function(e,n){e.constructor==String?e=n&&\"binary\"===n.encoding?o.stringToBytes(e):r.stringToBytes(e):i(e)?e=Array.prototype.slice.call(e,0):Array.isArray(e)||(e=e.toString());for(var a=t.bytesToWords(e),u=8*e.length,c=1732584193,l=-271733879,h=-1732584194,f=271733878,d=0;d<a.length;d++)a[d]=16711935&(a[d]<<8|a[d]>>>24)|4278255360&(a[d]<<24|a[d]>>>8);a[u>>>5]|=128<<u%32,a[(u+64>>>9<<4)+14]=u;for(var p=s._ff,_=s._gg,v=s._hh,y=s._ii,d=0;d<a.length;d+=16){var m=c,g=l,b=h,w=f;c=p(c,l,h,f,a[d+0],7,-680876936),f=p(f,c,l,h,a[d+1],12,-389564586),h=p(h,f,c,l,a[d+2],17,606105819),l=p(l,h,f,c,a[d+3],22,-1044525330),c=p(c,l,h,f,a[d+4],7,-176418897),f=p(f,c,l,h,a[d+5],12,1200080426),h=p(h,f,c,l,a[d+6],17,-1473231341),l=p(l,h,f,c,a[d+7],22,-45705983),c=p(c,l,h,f,a[d+8],7,1770035416),f=p(f,c,l,h,a[d+9],12,-1958414417),h=p(h,f,c,l,a[d+10],17,-42063),l=p(l,h,f,c,a[d+11],22,-1990404162),c=p(c,l,h,f,a[d+12],7,1804603682),f=p(f,c,l,h,a[d+13],12,-40341101),h=p(h,f,c,l,a[d+14],17,-1502002290),l=p(l,h,f,c,a[d+15],22,1236535329),c=_(c,l,h,f,a[d+1],5,-165796510),f=_(f,c,l,h,a[d+6],9,-1069501632),h=_(h,f,c,l,a[d+11],14,643717713),l=_(l,h,f,c,a[d+0],20,-373897302),c=_(c,l,h,f,a[d+5],5,-701558691),f=_(f,c,l,h,a[d+10],9,38016083),h=_(h,f,c,l,a[d+15],14,-660478335),l=_(l,h,f,c,a[d+4],20,-405537848),c=_(c,l,h,f,a[d+9],5,568446438),f=_(f,c,l,h,a[d+14],9,-1019803690),h=_(h,f,c,l,a[d+3],14,-187363961),l=_(l,h,f,c,a[d+8],20,1163531501),c=_(c,l,h,f,a[d+13],5,-1444681467),f=_(f,c,l,h,a[d+2],9,-51403784),h=_(h,f,c,l,a[d+7],14,1735328473),l=_(l,h,f,c,a[d+12],20,-1926607734),c=v(c,l,h,f,a[d+5],4,-378558),f=v(f,c,l,h,a[d+8],11,-2022574463),h=v(h,f,c,l,a[d+11],16,1839030562),l=v(l,h,f,c,a[d+14],23,-35309556),c=v(c,l,h,f,a[d+1],4,-1530992060),f=v(f,c,l,h,a[d+4],11,1272893353),h=v(h,f,c,l,a[d+7],16,-155497632),l=v(l,h,f,c,a[d+10],23,-1094730640),c=v(c,l,h,f,a[d+13],4,681279174),f=v(f,c,l,h,a[d+0],11,-358537222),h=v(h,f,c,l,a[d+3],16,-722521979),l=v(l,h,f,c,a[d+6],23,76029189),c=v(c,l,h,f,a[d+9],4,-640364487),f=v(f,c,l,h,a[d+12],11,-421815835),h=v(h,f,c,l,a[d+15],16,530742520),l=v(l,h,f,c,a[d+2],23,-995338651),c=y(c,l,h,f,a[d+0],6,-198630844),f=y(f,c,l,h,a[d+7],10,1126891415),h=y(h,f,c,l,a[d+14],15,-1416354905),l=y(l,h,f,c,a[d+5],21,-57434055),c=y(c,l,h,f,a[d+12],6,1700485571),f=y(f,c,l,h,a[d+3],10,-1894986606),h=y(h,f,c,l,a[d+10],15,-1051523),l=y(l,h,f,c,a[d+1],21,-2054922799),c=y(c,l,h,f,a[d+8],6,1873313359),f=y(f,c,l,h,a[d+15],10,-30611744),h=y(h,f,c,l,a[d+6],15,-1560198380),l=y(l,h,f,c,a[d+13],21,1309151649),c=y(c,l,h,f,a[d+4],6,-145523070),f=y(f,c,l,h,a[d+11],10,-1120210379),h=y(h,f,c,l,a[d+2],15,718787259),l=y(l,h,f,c,a[d+9],21,-343485551),c=c+m>>>0,l=l+g>>>0,h=h+b>>>0,f=f+w>>>0}return t.endian([c,l,h,f])};s._ff=function(e,t,n,r,i,o,s){var a=e+(t&n|~t&r)+(i>>>0)+s;return(a<<o|a>>>32-o)+t},s._gg=function(e,t,n,r,i,o,s){var a=e+(t&r|n&~r)+(i>>>0)+s;return(a<<o|a>>>32-o)+t},s._hh=function(e,t,n,r,i,o,s){var a=e+(t^n^r)+(i>>>0)+s;return(a<<o|a>>>32-o)+t},s._ii=function(e,t,n,r,i,o,s){var a=e+(n^(t|~r))+(i>>>0)+s;return(a<<o|a>>>32-o)+t},s._blocksize=16,s._digestsize=16,e.exports=function(e,n){if(void 0===e||null===e)throw new Error(\"Illegal argument \"+e);var r=t.wordsToBytes(s(e,n));return n&&n.asBytes?r:n&&n.asString?o.bytesToString(r):t.bytesToHex(r)}}()},function(e,t){function n(e){if(e=String(e),!(e.length>1e4)){var t=/^((?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var n=parseFloat(t[1]),r=(t[2]||\"ms\").toLowerCase();switch(r){case\"years\":case\"year\":case\"yrs\":case\"yr\":case\"y\":return n*l;case\"days\":case\"day\":case\"d\":return n*c;case\"hours\":case\"hour\":case\"hrs\":case\"hr\":case\"h\":return n*u;case\"minutes\":case\"minute\":case\"mins\":case\"min\":case\"m\":return n*a;case\"seconds\":case\"second\":case\"secs\":case\"sec\":case\"s\":return n*s;case\"milliseconds\":case\"millisecond\":case\"msecs\":case\"msec\":case\"ms\":return n;default:return}}}}function r(e){return e>=c?Math.round(e/c)+\"d\":e>=u?Math.round(e/u)+\"h\":e>=a?Math.round(e/a)+\"m\":e>=s?Math.round(e/s)+\"s\":e+\"ms\"}function i(e){return o(e,c,\"day\")||o(e,u,\"hour\")||o(e,a,\"minute\")||o(e,s,\"second\")||e+\" ms\"}function o(e,t,n){if(!(e<t))return e<1.5*t?Math.floor(e/t)+\" \"+n:Math.ceil(e/t)+\" \"+n+\"s\"}var s=1e3,a=60*s,u=60*a,c=24*u,l=365.25*c;e.exports=function(e,t){t=t||{};var o=typeof e;if(\"string\"===o&&e.length>0)return n(e);if(\"number\"===o&&isNaN(e)===!1)return t.long?i(e):r(e);throw new Error(\"val is not a non-empty string or a valid number. val=\"+JSON.stringify(e))}},function(e,t,n){function r(e){var t=i(e)?Object.prototype.toString.call(e):\"\";return\"[object Function]\"===t}var i=n(11);e.exports=r},function(e,t,n){function r(e){if(e)return i(e)}function i(e){for(var t in r.prototype)e[t]=r.prototype[t];return e}var o=n(11);e.exports=r,r.prototype.clearTimeout=function(){return clearTimeout(this._timer),clearTimeout(this._responseTimeoutTimer),delete this._timer,delete this._responseTimeoutTimer,this},r.prototype.parse=function(e){return this._parser=e,this},r.prototype.responseType=function(e){return this._responseType=e,this},r.prototype.serialize=function(e){return this._serializer=e,this},r.prototype.timeout=function(e){if(!e||\"object\"!=typeof e)return this._timeout=e,this._responseTimeout=0,this;for(var t in e)switch(t){case\"deadline\":this._timeout=e.deadline;break;case\"response\":this._responseTimeout=e.response;break;default:console.warn(\"Unknown timeout option\",t)}return this},r.prototype.retry=function(e){return 0!==arguments.length&&e!==!0||(e=1),e<=0&&(e=0),this._maxRetries=e,this._retries=0,this},r.prototype._retry=function(){return this.clearTimeout(),this.req&&(this.req=null,this.req=this.request()),this._aborted=!1,this.timedout=!1,this._end()},r.prototype.then=function(e,t){if(!this._fullfilledPromise){var n=this;this._endCalled&&console.warn(\"Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises\"),this._fullfilledPromise=new Promise(function(e,t){n.end(function(n,r){n?t(n):e(r)})})}return this._fullfilledPromise.then(e,t)},r.prototype.catch=function(e){return this.then(void 0,e)},r.prototype.use=function(e){return e(this),this},r.prototype.ok=function(e){if(\"function\"!=typeof e)throw Error(\"Callback required\");return this._okCallback=e,this},r.prototype._isResponseOK=function(e){return!!e&&(this._okCallback?this._okCallback(e):e.status>=200&&e.status<300)},r.prototype.get=function(e){return this._header[e.toLowerCase()]},r.prototype.getHeader=r.prototype.get,r.prototype.set=function(e,t){if(o(e)){for(var n in e)this.set(n,e[n]);return this}return this._header[e.toLowerCase()]=t,this.header[e]=t,this},r.prototype.unset=function(e){return delete this._header[e.toLowerCase()],delete this.header[e],this},r.prototype.field=function(e,t){if(null===e||void 0===e)throw new Error(\".field(name, val) name can not be empty\");if(this._data&&console.error(\".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()\"),o(e)){for(var n in e)this.field(n,e[n]);return this}if(Array.isArray(t)){for(var r in t)this.field(e,t[r]);return this}if(null===t||void 0===t)throw new Error(\".field(name, val) val can not be empty\");return\"boolean\"==typeof t&&(t=\"\"+t),this._getFormData().append(e,t),this},r.prototype.abort=function(){return this._aborted?this:(this._aborted=!0,this.xhr&&this.xhr.abort(),this.req&&this.req.abort(),this.clearTimeout(),this.emit(\"abort\"),this)},r.prototype.withCredentials=function(e){return void 0==e&&(e=!0),this._withCredentials=e,this},r.prototype.redirects=function(e){return this._maxRedirects=e,this},r.prototype.toJSON=function(){return{method:this.method,url:this.url,data:this._data,headers:this._header}},r.prototype.send=function(e){var t=o(e),n=this._header[\"content-type\"];if(this._formData&&console.error(\".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()\"),t&&!this._data)Array.isArray(e)?this._data=[]:this._isHost(e)||(this._data={});else if(e&&this._data&&this._isHost(this._data))throw Error(\"Can't merge these send calls\");if(t&&o(this._data))for(var r in e)this._data[r]=e[r];else\"string\"==typeof e?(n||this.type(\"form\"),n=this._header[\"content-type\"],\"application/x-www-form-urlencoded\"==n?this._data=this._data?this._data+\"&\"+e:e:this._data=(this._data||\"\")+e):this._data=e;return!t||this._isHost(e)?this:(n||this.type(\"json\"),this)},r.prototype.sortQuery=function(e){return this._sort=\"undefined\"==typeof e||e,this},r.prototype._timeoutError=function(e,t,n){if(!this._aborted){var r=new Error(e+t+\"ms exceeded\");r.timeout=t,r.code=\"ECONNABORTED\",r.errno=n,this.timedout=!0,this.abort(),this.callback(r)}},r.prototype._setTimeouts=function(){var e=this;this._timeout&&!this._timer&&(this._timer=setTimeout(function(){e._timeoutError(\"Timeout of \",e._timeout,\"ETIME\")},this._timeout)),this._responseTimeout&&!this._responseTimeoutTimer&&(this._responseTimeoutTimer=setTimeout(function(){e._timeoutError(\"Response timeout of \",e._responseTimeout,\"ETIMEDOUT\")},this._responseTimeout))}},function(e,t,n){function r(e){if(e)return i(e)}function i(e){for(var t in r.prototype)e[t]=r.prototype[t];return e}var o=n(64);e.exports=r,r.prototype.get=function(e){return this.header[e.toLowerCase()]},r.prototype._setHeaderProperties=function(e){var t=e[\"content-type\"]||\"\";this.type=o.type(t);var n=o.params(t);for(var r in n)this[r]=n[r];this.links={};try{e.link&&(this.links=o.parseLinks(e.link))}catch(e){}},r.prototype._setStatusProperties=function(e){var t=e/100|0;this.status=this.statusCode=e,this.statusType=t,this.info=1==t,this.ok=2==t,this.redirect=3==t,this.clientError=4==t,this.serverError=5==t,this.error=(4==t||5==t)&&this.toError(),this.accepted=202==e,this.noContent=204==e,this.badRequest=400==e,this.unauthorized=401==e,this.notAcceptable=406==e,this.forbidden=403==e,this.notFound=404==e}},function(e,t){var n=[\"ECONNRESET\",\"ETIMEDOUT\",\"EADDRINFO\",\"ESOCKETTIMEDOUT\"];e.exports=function(e,t){return!!(e&&e.code&&~n.indexOf(e.code))||(!!(t&&t.status&&t.status>=500)||(!!(e&&\"timeout\"in e&&\"ECONNABORTED\"==e.code)||!!(e&&\"crossDomain\"in e)))}},function(e,t){t.type=function(e){return e.split(/ *; */).shift()},t.params=function(e){return e.split(/ *; */).reduce(function(e,t){var n=t.split(/ *= */),r=n.shift(),i=n.shift();return r&&i&&(e[r]=i),e},{})},t.parseLinks=function(e){return e.split(/ *, */).reduce(function(e,t){var n=t.split(/ *; */),r=n[0].slice(1,-1),i=n[1].split(/ *= */)[1].slice(1,-1);return e[i]=r,e},{})},t.cleanHeader=function(e,t){return delete e[\"content-type\"],delete e[\"content-length\"],delete e[\"transfer-encoding\"],delete e.host,t&&delete e.cookie,e}},function(e,t){}])});\n//# sourceMappingURL=av-weapp-min.js.map\n"
  },
  {
    "path": "ofo 无微信支付/utils/base.js",
    "content": "import {Config} from \"config.js\";\nclass Base {\n  constructor(){\n    this.baseRequestUrl = Config.baseUrl;\n  }\n\n//封装好的请求方法\n  requet(params) {\n    if(!params.type) {\n      params.type = \"GET\";\n    }\n\n    wx.request({\n      url: this.baseRequestUrl+params.url,\n      data: params.data,\n      header: {\n        'content-type':'application/json',\n        'token':wx.getStorageSync('token')\n      },\n      method: params.type,\n      success: function(res) {\n        sCallBack && sCallBack(res);\n      },\n      fail: function(res) {\n        console.log(res);\n      },\n      complete: function(res) {},\n    })\n  }\n\n}\nexport{Base}"
  },
  {
    "path": "ofo 无微信支付/utils/config.js",
    "content": "class Config {\n  constructor(){\n\n  }\n}\nConfig.baseUrl = \"http://www.ofo.com/qpi/v1/\";\n\nexport{Config};"
  },
  {
    "path": "ofo 无微信支付/utils/util.js",
    "content": "function formatTime(date) {\n  var year = date.getFullYear()\n  var month = date.getMonth() + 1\n  var day = date.getDate()\n\n  var hour = date.getHours()\n  var minute = date.getMinutes()\n  var second = date.getSeconds()\n\n\n  return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')\n}\n\nfunction formatNumber(n) {\n  n = n.toString()\n  return n[1] ? n : '0' + n\n}\n\nmodule.exports = {\n  formatTime: formatTime\n}"
  },
  {
    "path": "phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit backupGlobals=\"false\"\n         backupStaticAttributes=\"false\"\n         colors=\"true\"\n         convertErrorsToExceptions=\"true\"\n         convertNoticesToExceptions=\"true\"\n         convertWarningsToExceptions=\"true\"\n         processIsolation=\"false\"\n         stopOnFailure=\"false\"\n         syntaxCheck=\"false\">\n    <testsuites>\n        <testsuite name=\"Application Test Suite\">\n            <directory>./tests/</directory>\n        </testsuite>\n    </testsuites>\n    <filter>\n        <whitelist>\n            <directory suffix=\".php\">application/</directory>\n        </whitelist>\n    </filter>\n</phpunit>\n"
  },
  {
    "path": "public/.htaccess",
    "content": "<IfModule mod_rewrite.c>\n  Options +FollowSymlinks -Multiviews\n  RewriteEngine On\n\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]\n</IfModule>\n"
  },
  {
    "path": "public/index.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n// [ 应用入口文件 ]\n\n// 定义应用目录\ndefine('APP_PATH', __DIR__ . '/../application/');\n// 加载框架引导文件\nrequire __DIR__ . '/../thinkphp/start.php';\n"
  },
  {
    "path": "public/robots.txt",
    "content": "User-agent: *\nDisallow:\n"
  },
  {
    "path": "public/router.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n// $Id$\n\nif (is_file($_SERVER[\"DOCUMENT_ROOT\"] . $_SERVER[\"REQUEST_URI\"])) {\n    return false;\n} else {\n    require __DIR__ . \"/index.php\";\n}\n"
  },
  {
    "path": "public/static/.gitignore",
    "content": "!.gitignore"
  },
  {
    "path": "public/static/admin/common.css",
    "content": ".tp5 >ul>li{\n    display: inline-block;\n    width:20px;\n    color: #337ab7;\n    text-align: center;\n    margin-left: 5px;\n}"
  },
  {
    "path": "public/static/admin/js/common.js",
    "content": "/**\n * 添加\n * @param title\n * @param url\n */\n  function edit_add(title,url) {\n      var index = layer.open({\n          type:2,\n          content:url,\n          title:title,\n      });\n      layer.full(index);\n  }\n\n/*添加或者编辑缩小的屏幕*/\nfunction yfy_s_edit(title,url,w,h){\n    layer_show(title,url,w,h);\n}\n\n/*\n* 提交form表单操作\n*\n* */\n$(\"#yfycms-button-submit\").click(function(){\n    var data=$(\"#yfycms-form\").serializeArray();\n    console.log(data);\n    postData={};\n    $(data).each(function(i){\n        postData[this.name]=this.value;\n    });\n    console.log(postData);\n    url=SCOPE.save_url;\n    jump_url=SCOPE.jump_url;\n    $.post(url,postData,function($result){\n        if($result.status == 1){\n            return dialogs.success($result.message,jump_url);\n        }else if($result.status == 0){\n            return dialogs.error($result.message);\n        }\n    },\"JSON\");\n});\n\n/**\n * 删除操作采用了layer插件和异步加载方式和修改状态公用的方法\n */\n$(' .app-status').click(function(){\n    var id = $(this).attr('attr-id');\n    var message=$(this).attr('attr-message');\n    var url = SCOPE.status_url;\n    data={};\n    data['id'] = id;\n    data['status'] = $(this).attr('attr-status');\n\n    layer.open({\n        type : 0,\n        title : '是否提交？',\n        btn : ['yes','no'],\n        icon :3,\n        closeBtn : 2,\n        content : '是否确认'+message,\n        scorllbar : true,\n        yes: function(){\n            todelete(url,data);\n        },\n    });\n});\n\nfunction todelete(){\n    var url = SCOPE.status_url;\n    var jump_url = SCOPE.jump_url;\n    //ajax的异步操作，交互性好\n    $.post(\n        url,data,function(s){\n            console.log(s);\n            if(s.status == 1){\n                return dialogs.success(s.message,jump_url);\n            }else{\n                return dialogs.error(s.message);\n            }\n        },\"JSON\");\n}\n\n"
  },
  {
    "path": "public/static/admin/js/dialog.js",
    "content": "\n    var dialogs = {\n        // 错误弹出层\n        error: function(message) {\n            layer.open({\n                content:message,\n                icon:2,\n                title : '错误提示',\n            });\n        },\n\n        //成功弹出层\n        success : function(message,url) {\n            layer.open({\n                content : message,\n                icon : 1,\n                yes : function(){\n                    location.href=url;\n                },\n            });\n        },\n\n        // 确认弹出层\n        confirm : function(message, url) {\n            layer.open({\n                content : message,\n                icon:3,\n                btn : ['是','否'],\n                yes : function(){\n                    location.href=url;\n                },\n            });\n        },\n\n        //无需跳转到指定页面的确认弹出层\n        toconfirm : function(message) {\n            layer.open({\n                content : message,\n                icon:3,\n                btn : ['确定'],\n            });\n        },\n    }\n"
  },
  {
    "path": "public/static/h-ui/css/H-ui.css",
    "content": "@charset \"utf-8\";\n/* -----------H-ui前端框架-------------\n* H-ui.css v3.1.5\n* http://www.h-ui.net/\n* Created & Modified by guojunhui\n* Date modified 2017.07.19\n*\n* Copyright 2013-2017 北京颖杰联创科技有限公司 All rights reserved.\n* Licensed under MIT license.\n* http://opensource.org/licenses/MIT\n*\n*/\n/*------------------------------------\n结构目录：\n  1. css reset重定义浏览器默认样式\n  2. 框架\n    2.1 响应式栅格系统\n    2.2 响应式隐藏显示\n  3. 基础CSS\n    3.1 排版\n      3.1.1  标题\n      3.1.2  强调\n      3.1.3  对齐\n      3.1.4  定位\n      3.1.5  浮动\n\t  3.1.6  文字单行溢出省略号\n\t  3.1.7  线条\n      3.1.8  外边距\n      3.1.9  内填充\n      3.1.10 边框，css3圆角\n      3.1.11 css3阴影\n      3.1.12 行内分割竖线\n      3.1.13 文字尺寸\n      3.1.14 文字行距\n      3.1.15 文字颜色\n      3.1.16 文字颜色强调\n      3.1.17 缩略语\n      3.1.18 地址\n      3.1.19 引用\n      3.1.20 上标 下标\n      3.1.21 内容样式\n      3.1.22 列表\n      3.1.23 描述\n\t  3.1.24 隐藏 显示\n\t  3.1.25 尺寸\n    3.2 代码\n    3.3 表格\n    3.4 表单\n      3.4.1 input,textarea 文本域 文本区域\n      3.4.2 radio,checkbox 单选 多选\n\t  \t3.4.2.1 jQuery.icheck.css\n\t\t3.4.2.2 Bootsrtap.Switch.css\n      3.4.3 select 下拉框\n      3.4.4 input-file 文件上传\n\t  3.4.5 spinner 控件\n\t  3.4.6 邮箱提示\n      3.4.7 表单布局\n\t  3.4.8 表单验证\t  \n    3.5 按钮\n    3.6 图片\n    3.7 图标\n    3.8 动画\n  4. 组件\n    4.1 按钮组\n    4.2 导航\n      4.2.1 导航条\n      4.2.2 面包屑导航\n      4.2.3 翻页导航\n\t  4.2.4 顶部导航\n\t  4.2.5 向导\n\t  4.2.6 竖向导向tab导航\n\t  4.2.7 横向tab\n    4.3 菜单\n      4.3.1 下拉菜单\n      4.3.2 多级菜单\n      4.3.3 树状菜单（暂无）\n    4.4 幻灯片\n      4.4.1 焦点图效果(自动播放，圆点控制)\n      4.4.2 带缩略图效果\n    4.5 选项卡\n    4.6 便签与标号\n    4.7 缩略图\n    4.8 警告\n    4.9 进度条 loading\n    4.10 对话框 弹出层\n    4.11 客服\n    4.12 右侧悬浮工具\n\t\t4.12.1 返回顶部\n\t\t4.12.2 意见反馈\n    4.13 分享\n    4.14 面板\n    4.15 案例\n    4.16 滚动\n    4.17 搜索\n    4.18 广告\n    4.19 标签\n      4.19.1 标签输入效果\n      4.19.2 标签混排效果\n      4.19.3 tag云标签\n    4.20 折叠\n    4.21 遮罩条\n    4.22 评论列表\n\t4.23 页脚\n\t4.24 星星评价\n\t4.25 tooltip效果\n\t4.26 popover效果\n\t4.27 datetimepicker日期插件\n\t4.28 sortable拖动\n\t4.29 ColorPicker 颜色控件\n  5. 页面\n    5.1 404页面\n    5.2 博客列表页（暂无）\n    5.3 博客详情页（暂无）\n    5.4 关于我们页（暂无）\n    5.5 帮助列表页（暂无）\n    5.6 帮助详情页（暂无）\n\n----------------------------------\nCSS写作注意事项：\n  1. 页面编码规范\n    1.1. 统一使用 UTF-8 编码,用@charset \"utf-8\"指定页面编码。\n    1.2. 全局字体设置：\n         windows 7系统：微软雅黑 Arial；\n         windows XP及以下：新宋体，宋体，Arial\n         MAC默认字体：Helvetica Neue和Helvetica Hiragino Sans GB。\n    1.3. 中文字体使用编码转换，请参阅下节“中文字体css编码转换”\n    1.4. 推荐使用216web安全色\n  2. 属性写在一行内，属性之间、属性名和值之间以及属性与“{}”之间应减少空格，去掉最后一个“;”，例如：.class{width:200px;height:100px}\n  3. 属性的书写顺序：\n    3.1. 按照元素模型由外及内，由整体到细节书写，大致分为五组：\n      位置：position,left,right,float\n      盒模型属性：display,margin,padding,width,height\n      边框与背景：border,background\n      段落与文本：line-height,text-indent,font,color,text-decoration,...\n      其他属性：overflow,cursor,visibility,...\n    3.2. 针对特殊浏览器的属性，应写在标准属性之前，例如：-webkit-box-shadow:;-moz-box-shadow:;box-shaow:;\n  4. 带有前缀的属性，单独一行，通过缩进，让每个属性的值垂直对齐，方便编辑维护。\n  5. 谨慎添加新的选择符规则，尤其不可滥用 id，尽可能继承和复用已有样式\n  6. 选择符、属性、值均用小写（格式的颜色值除外），缩写的选择符名称须说明缩写前的全称，例如 .cl -> Clearfix\n  7. 避免使用各种 CSS Hack，如需对 IE 进行特殊定义，请参阅下节“关于 CSS Hack 的说明”\n  8. 勿使用冗余低效的 CSS 写法，例如：ul li a span{... }\n  9. 慎用 !important\n  10. 建议使用具有语义化的classname或id，请参阅下节“css 命名规范及对应的缩写”\n  11.避免使用兼容性不好的使用滤镜\n  12.开发过程中的未定事项，须用 [!] 标出，以便于后续讨论整理。\n  13.注释格式，统一使用双斜杠加*。\n  14.上下模块之间的间距统一使用下一个模块的margin-top来实现，好处是：如果没有下一个模块也不会多出一段空隙。\n  15.hover，selected，disabled，current等具有特定意义的请勿直接占用。\n  16.:link :visited :hover :active书写顺序 L-V-H-A，速记：LoVe（喜欢）HAte（讨厌）。\n  17.不要使用 @import\n----------------------------------\n中文字体css编码转换\n  微软雅黑   \\5FAE\\8F6F\\96C5\\9ED1  或 Microsoft YaHei\n  黑体       \\9ED1\\4F53\n  新宋体     \\65b0\\5b8b\\4f53\n  宋体       \\5b8b\\4f53\n----------------------------------\n关于 CSS Hack 的说明：\n  1. _          IE6\n  2. *          IE6/7\n  3. !important IE7/Firefox\n  4. *+         IE7\n  5. \\9         IE6/7/8\n  6. \\0         IE8\n  7. 条件hack\n      <!--[if lt IE 7]><html class=\"no-js lt-ie9 lt-ie8 lt-ie7\"><![endif]--> IE7以下版本\n      <!--[if IE 7]><html class=\"no-js lt-ie9 lt-ie8\"><![endif]--> IE7\n      <!--[if IE 8]> <html class=\"no-js lt-ie9\"><![endif]--> IE8\n      <!--[if gt IE 8]><!--><html class=\"no-js\"><!--<![endif]--> IE8以上\n----------------------------------\ncss 命名规范\n  1. 内容优先,表现为辅\n  2. css命名中英文对照\n  current 当前    hover 悬停    selected 挑选   disabled 禁用   focus 得到焦点    blur 失去焦点   checked 勾选    success 成功    error 出错\n\n  header(hd) 头部   content(cnt) 内容   title(tit) 标题   item 项目（条）    cell 单元   image/pic(img) 图片   text(txt) 文字    top 顶部    scrubber 时序菜单\n\n  nav 导航    mainNav 主导航   subNav 子导航    topNav 顶部导航   breadcrumb 面包屑导航\n\n  flink 友情链接    footer 尾    copyright 版权\n\n  menu 菜单   submenu 子菜单   dropdown 下拉菜单\n\n  searchBar 搜索条   search 搜索条    searchTxt 搜索框   searchBtn 搜索按钮    search_key 搜索词\n\n  member 会员   ucenter 用户中心    loginBar 登陆条    login 登录    loginBtn 登录按钮   regsiter 注册按钮   btn-regsiter注册按钮    name 用户名    password 密码   nickname 昵称   mobilephone/mobile 手机    telephone/tel 电话   defaultavatar 默认头像\n\n  hot 热点    news 新闻   banner/AD 广告    download 下载\n\n  content 内容    title 标题    summary 摘要    time 时间\n\n  share 分享    digg 顶    like 喜欢\n\n  list/-list 列表   pList 图片列表    tList 文字列表    tpList 图文列表\n\n  table 表格    row 行   column 列    gutter 间隔   viewport 视口\n\n  tab 标签    tags 标签   scroll 滚动\n\n  sidebar 侧边栏   column 栏目   section 区块    msg 提示信息    status 状态   vote 投票   tips 小技巧    guild 指南    note 注释\n\n  icon- 图标    btn- 按钮\n\n  goods 商品    goods-list 商品列表    goods-detail 商品详情    goods-info 商品信息\n\n  tuan 团购   tuan-list 团购列表   tuan-detail  团购详情    tuan-info 团购信息\n\n  transition 动画   shadow 阴影   fade 淡入淡出   flip 翻页效    slide 滑动    slideup 上滑动   slidedown 下滑动   turn 翻页   horizontal 水平   vertical 垂直   collapsible 折叠    corners 拐角    flow 流    reverse 反向    pop 弹窗\n\n  count 总数/计数   plus 加号/正   minus 减号/负    controlgroup 控制组\n----------------------------------\nhtml命名规范：\n  default/index.html    首页\n  404.html              404错误页\n  print.html            打印页\n  header.html           页头\n  footer.html           页脚\n  sitemap.html          网站地图\n  passport.html         通行证\n  rank.html             排行榜\n  roll.html             滚动新闻\n\n  solution.html         解决方案\n  joinus.html           加入我们\n  partner.html          合作伙伴\n  service.html          服务\n  aboutus.html          关于我们\n  contact.html          联系我们\n  company.html          公司介绍\n  organization.html     组织结构\n  culture.html          企业文化\n  strategy.html         发展策略\n  honor.html            公司荣誉\n  aptitudes.html        企业资质\n  events.html           大事记\n  business.html         商务合作\n  contract.html         服务条款\n  privacy.html          隐私声明\n  CSR.html              企业社会责任\n\n  news-开头.html         新闻相关\n  article-开头.html      资讯相关\n  picture-开头.html      图片相关\n  photo-开头.html        相册相关\n  product-开头.html      产品相关\n  goods-开头.html        商品相关\n  system-开头.html       系统相关\n  tag-开头.html          tag相关\n  brand-开头.html        品牌相关\n  help-开头.html         帮助相关\n  member-开头.html       会员相关\n  search-开头.html       搜索相关\n---------------------------------- */\n/*1 重定义浏览器默认样式\n\tName:\t\t\tstyle_reset\n\tExplain:\t\t重定义浏览器默认样式\n*/\n*{word-wrap:break-word}\nhtml,body,h1,h2,h3,h4,h5,h6,hr,p,iframe,dl,dt,dd,ul,ol,li,pre,form,button,input,textarea,th,td,fieldset{margin:0;padding:0}\nul,ol,dl{list-style-type:none}\nhtml,body{*position:static}\nhtml{font-family: sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}\naddress,caption,cite,code,dfn,em,th,var{font-style:normal;font-weight:400}\ninput,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit}\ninput,button{overflow: visible;vertical-align:middle;outline:none}\ninput[type=\"submit\"],input[type=\"reset\"],input[type=\"button\"],input[type=\"text\"],input[type=\"password\"]{-webkit-appearance:none;outline:none}\nbody,th,td,button,input,select,textarea{font-family:\"Microsoft Yahei\",\"Hiragino Sans GB\",\"Helvetica Neue\",Helvetica,tahoma,arial,\"WenQuanYi Micro Hei\",Verdana,sans-serif,\"\\5B8B\\4F53\";font-size:12px;color: #333;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing:grayscale}\n@media ( max-width : 767px) {\n\thtml{ overflow-y:auto}\n\tbody,th,td,button,input,select,textarea{ font-size:14px}\n}\nbody{line-height:1.6; position:relative}\nh1,h2,h3,h4,h5,h6{font-size:100%}\na,area{outline:none;blr:expression(this.onFocus=this.blur())}\na{text-decoration:none;cursor: pointer}\na:hover{text-decoration:underline;outline:none}\na.ie6:hover{zoom:1}\na:focus{outline:none}\na:hover,a:active{outline:none}:focus{outline:none}\nsub,sup{vertical-align:baseline}\nbutton,input[type=\"button\"], input[type=\"submit\"] {line-height:normal !important}\n/*img*/\nimg{border:0;vertical-align:middle}\na img,img{-ms-interpolation-mode:bicubic}\n\n/*IE下a:hover 背景闪烁*/\n*html{overflow:-moz-scrollbars-vertical;zoom:expression(function(ele){ele.style.zoom = \"1\";document.execCommand(\"BackgroundImageCache\",false,true)}(this))}\n\n/*HTML5 reset*/\nheader,footer,section,aside,details,menu,article,section,nav,address,hgroup,figure,figcaption,legend{display:block;margin:0;padding:0}time{display:inline}\naudio,canvas,video{display:inline-block;*display:inline;*zoom:1}\naudio:not([controls]){display:none}\nlegend{width:100%;margin-bottom:20px;font-size:21px;line-height:40px;border:0;border-bottom:1px solid #e5e5e5}\nlegend small{font-size:15px;color:#999}\nsvg:not(:root) {overflow: hidden}\nfieldset {border-width:0;padding: 0.35em 0.625em 0.75em;margin: 0 2px;border: 1px solid #c0c0c0}\ninput[type=\"number\"]::-webkit-inner-spin-button,input[type=\"number\"]::-webkit-outer-spin-button {height: auto}\ninput[type=\"search\"] {-webkit-appearance: textfield; /* 1 */}\ninput[type=\"search\"]::-webkit-search-cancel-button,input[type=\"search\"]::-webkit-search-decoration {-webkit-appearance: none}\n/*清除浮动\n\tName:\t\t\tstyle_clearfix\n\tExample:\t\tclass=\"clearfix|cl\"\n\tExplain:\t\tclearfix（简写cl）避免因子元素浮动而导致的父元素高度缺失能问题\n*/\n.cl:after,.clearfix:after{content:\"\\20\";display:block;height:0;clear:both;visibility:hidden}.cl,.clearfix{zoom:1}\n\n/*2.1 栅格系统\n\tName:\t\t\tstyle_container\n\tExample:\n\t<div class=\"responsive\">\n\t<div class=\"row cl\" role=\"grid\">\n\t  <div class=\"col-1\">……</div>\n\t  ……\n\t</div>\n\t</div>\n\tExplain:\t\t栅格系统\n*/\n/*2.1 响应式栅格系统*/\n.container {padding-right: 15px;padding-left: 15px;margin-right: auto;margin-left: auto}\n.container-fluid {padding-right: 15px;padding-left: 15px;margin-right: auto;margin-left: auto}\n\n@media ( min-width : 992px) {\n\t.container{width: 960px}\n}\n@media ( min-width : 1200px) {\n\t.container {width: 1170px}\n}\n@media ( min-width : 1300px) {\n\t.container {width: 1270px}\n}\n\n@media print{\n\t.container{width:auto}\n}\n.row.cl{}\n.row{box-sizing:border-box; margin-left:-15px; margin-right:-15px}\n.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.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 {min-height: 1px;position: relative; padding-left:15px; padding-right:15px; box-sizing:border-box;-webkit-transition:all 0.3s ease-in;\n\t\t-moz-transition:all 0.3s ease-in;\n\t\t-o-transition:all 0.3s ease-in;\n\t\t\ttransition:all 0.3s ease-in}\n\n.col-1{width:8.33333%}\n.col-2{width:16.66667%}\n.col-3{width:25%}\n.col-4{width:33.33333%}\n.col-5{width:41.66667%}\n.col-6{width:50%}\n.col-7{width:58.33333%}\n.col-8{width:66.66667%}\n.col-9{width:75%}\n.col-10{width:83.33333%}\n.col-11{width:91.66667%}\n.col-12{width:100%}\n\n.col-offset-0{margin-left:0}\n.col-offset-1{margin-left:8.33333%}\n.col-offset-2{margin-left:16.66667%}\n.col-offset-3{margin-left:25%}\n.col-offset-4{margin-left:33.33333%}\n.col-offset-5{margin-left:41.66667%}\n.col-offset-6{margin-left:50%}\n.col-offset-7{margin-left:58.33333%}\n.col-offset-8{margin-left:66.66667%}\n.col-offset-9{margin-left:75%}\n.col-offset-10{margin-left:83.33333%}\n.col-offset-11{margin-left:91.66667%}\n\n.col-push-0{position:relative;left:0;right:auto}\n.col-pull-0{right:0;left:auto}\n.col-push-1{left:8.33333%;right:auto}\n.col-pull-1{right:8.33333%;left:auto}\n.col-push-2{left:16.66667%;right:auto}\n.col-pull-2{right:16.66667%;left:auto}\n.col-push-3{left:25%;right:auto}\n.col-pull-3{right:25%;left:auto}\n.col-push-4{left:33.33333%;right:auto}\n.col-pull-4{right:33.33333%;left:auto}\n.col-push-5{left:41.66667%;right:auto}\n.col-pull-5{right:41.66667%;left:auto}\n.col-push-6{left:50%;right:auto}\n.col-pull-6{right:50%;left:auto}\n.col-push-7{left:58.33333%;right:auto}\n.col-pull-7{right:58.33333%;left:auto}\n.col-push-8{left:66.66667%;right:auto}\n.col-pull-8{right:66.66667%;left:auto}\n.col-push-9{left:75%;right:auto}\n.col-pull-9{right:75%;left:auto}\n.col-push-10{left:83.33333%;right:auto}\n.col-pull-10{right:83.33333%;left:auto}\n.col-push-11{left:91.66667%;right:auto}\n.col-pull-11{right:91.66667%;left:auto}\n/*局部模块平分*/\n.col-1-1{ width:100%}\n.col-2-1{ width:50%}\n.col-3-1{ width:33.333333%}\n.col-3-2{ width:66.666667%}\n.col-4-1{ width:25%}\n.col-4-3{ width:75%}\n.col-5-1{ width:20%}\n.col-5-2{ width:40%}\n.col-5-3{ width:60%}\n.col-5-4{ width:80%}\n.col-6-1{ width:16.666667%}\n.col-6-5{ width:83.333333%}\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 {float: left}\n.col-xs-12 {width: 100%}\n.col-xs-11 {width: 91.66666667%}\n.col-xs-10 {width: 83.33333333%}\n.col-xs-9 {width: 75%}\n.col-xs-8 {width: 66.66666667%}\n.col-xs-7 {width: 58.33333333%}\n.col-xs-6 {width: 50%}\n.col-xs-5 {width: 41.66666667%}\n.col-xs-4 {width: 33.33333333%}\n.col-xs-3 {width: 25%}\n.col-xs-2 {width: 16.66666667%}\n.col-xs-1 {width: 8.33333333%}\n.col-xs-pull-12 {right: 100%}\n.col-xs-pull-11 {right: 91.66666667%}\n.col-xs-pull-10 {right: 83.33333333%}\n.col-xs-pull-9 {right: 75%}\n.col-xs-pull-8 {right: 66.66666667%}\n.col-xs-pull-7 {right: 58.33333333%}\n.col-xs-pull-6 {right: 50%}\n.col-xs-pull-5 {right: 41.66666667%}\n.col-xs-pull-4 {right: 33.33333333%}\n.col-xs-pull-3 {right: 25%}\n.col-xs-pull-2 {right: 16.66666667%}\n.col-xs-pull-1 {right: 8.33333333%}\n.col-xs-pull-0 {right: auto}\n.col-xs-push-12 {left: 100%}\n.col-xs-push-11 {left: 91.66666667%}\n.col-xs-push-10 {left: 83.33333333%}\n.col-xs-push-9 {left: 75%}\n.col-xs-push-8 {left: 66.66666667%}\n.col-xs-push-7 {left: 58.33333333%}\n.col-xs-push-6 {left: 50%}\n.col-xs-push-5 {left: 41.66666667%}\n.col-xs-push-4 {left: 33.33333333%}\n.col-xs-push-3 {left: 25%}\n.col-xs-push-2 {left: 16.66666667%}\n.col-xs-push-1 {left: 8.33333333%}\n.col-xs-push-0 {left: auto}\n.col-xs-offset-12 {margin-left: 100%}\n.col-xs-offset-11 {margin-left: 91.66666667%}\n.col-xs-offset-10 {margin-left: 83.33333333%}\n.col-xs-offset-9 {margin-left: 75%}\n.col-xs-offset-8 {margin-left: 66.66666667%}\n.col-xs-offset-7 {margin-left: 58.33333333%}\n.col-xs-offset-6 {margin-left: 50%}\n.col-xs-offset-5 {margin-left: 41.66666667%}\n.col-xs-offset-4 {margin-left: 33.33333333%}\n.col-xs-offset-3 {margin-left: 25%}\n.col-xs-offset-2 {margin-left: 16.66666667%}\n.col-xs-offset-1 {margin-left: 8.33333333%}\n.col-xs-offset-0 {margin-left: 0}\n@media (max-width:767px){\n\t.responsive [class^=\"col-\"],.responsive [class*=\" col-\"]{float:none!important;width:auto!important}\n\t.responsive [class^=\"col-offset-\"],.responsive [class*=\" col-offset-\"]{ margin-left:0!important}\n}\n@media(min-width:768px){\n\t.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}\n\t.col-sm-12{width:100%}\n\t.col-sm-11{width:91.66666666666666%}\n\t.col-sm-10{width:83.33333333333334%}\n\t.col-sm-9{width:75%}\n\t.col-sm-8{width:66.66666666666666%}\n\t.col-sm-7{width:58.333333333333336%}\n\t.col-sm-6{width:50%}\n\t.col-sm-5{width:41.66666666666667%}\n\t.col-sm-4{width:33.33333333333333%}\n\t.col-sm-3{width:25%}\n\t.col-sm-2{width:16.666666666666664%}\n\t.col-sm-1{width:8.333333333333332%}\n\t.col-sm-pull-12{right:100%}\n\t.col-sm-pull-11{right:91.66666666666666%}\n\t.col-sm-pull-10{right:83.33333333333334%}\n\t.col-sm-pull-9{right:75%}\n\t.col-sm-pull-8{right:66.66666666666666%}\n\t.col-sm-pull-7{right:58.333333333333336%}\n\t.col-sm-pull-6{right:50%}\n\t.col-sm-pull-5{right:41.66666666666667%}\n\t.col-sm-pull-4{right:33.33333333333333%}\n\t.col-sm-pull-3{right:25%}\n\t.col-sm-pull-2{right:16.666666666666664%}\n\t.col-sm-pull-1{right:8.333333333333332%}\n\t.col-sm-pull-0{right:0}\n\t.col-sm-push-12{left:100%}\n\t.col-sm-push-11{left:91.66666666666666%}\n\t.col-sm-push-10{left:83.33333333333334%}\n\t.col-sm-push-9{left:75%}\n\t.col-sm-push-8{left:66.66666666666666%}\n\t.col-sm-push-7{left:58.333333333333336%}\n\t.col-sm-push-6{left:50%}\n\t.col-sm-push-5{left:41.66666666666667%}\n\t.col-sm-push-4{left:33.33333333333333%}\n\t.col-sm-push-3{left:25%}\n\t.col-sm-push-2{left:16.666666666666664%}\n\t.col-sm-push-1{left:8.333333333333332%}\n\t.col-sm-push-0{left:0}\n\t.col-sm-offset-12{margin-left:100%}\n\t.col-sm-offset-11{margin-left:91.66666666666666%}\n\t.col-sm-offset-10{margin-left:83.33333333333334%}\n\t.col-sm-offset-9{margin-left:75%}\n\t.col-sm-offset-8{margin-left:66.66666666666666%}\n\t.col-sm-offset-7{margin-left:58.333333333333336%}\n\t.col-sm-offset-6{margin-left:50%}\n\t.col-sm-offset-5{margin-left:41.66666666666667%}\n\t.col-sm-offset-4{margin-left:33.33333333333333%}\n\t.col-sm-offset-3{margin-left:25%}\n\t.col-sm-offset-2{margin-left:16.666666666666664%}\n\t.col-sm-offset-1{margin-left:8.333333333333332%}\n\t.col-sm-offset-0{margin-left:0}\n}\n@media(min-width:992px){\n\t.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}\n\t.col-md-12{width:100%}\n\t.col-md-11{width:91.66666666666666%}\n\t.col-md-10{width:83.33333333333334%}\n\t.col-md-9{width:75%}\n\t.col-md-8{width:66.66666666666666%}\n\t.col-md-7{width:58.333333333333336%}\n\t.col-md-6{width:50%}\n\t.col-md-5{width:41.66666666666667%}\n\t.col-md-4{width:33.33333333333333%}\n\t.col-md-3{width:25%}\n\t.col-md-2{width:16.666666666666664%}\n\t.col-md-1{width:8.333333333333332%}\n\t.col-md-pull-12{right:100%}\n\t.col-md-pull-11{right:91.66666666666666%}\n\t.col-md-pull-10{right:83.33333333333334%}\n\t.col-md-pull-9{right:75%}\n\t.col-md-pull-8{right:66.66666666666666%}\n\t.col-md-pull-7{right:58.333333333333336%}\n\t.col-md-pull-6{right:50%}\n\t.col-md-pull-5{right:41.66666666666667%}\n\t.col-md-pull-4{right:33.33333333333333%}\n\t.col-md-pull-3{right:25%}\n\t.col-md-pull-2{right:16.666666666666664%}\n\t.col-md-pull-1{right:8.333333333333332%}\n\t.col-md-pull-0{right:0}\n\t.col-md-push-12{left:100%}\n\t.col-md-push-11{left:91.66666666666666%}\n\t.col-md-push-10{left:83.33333333333334%}\n\t.col-md-push-9{left:75%}\n\t.col-md-push-8{left:66.66666666666666%}\n\t.col-md-push-7{left:58.333333333333336%}\n\t.col-md-push-6{left:50%}\n\t.col-md-push-5{left:41.66666666666667%}\n\t.col-md-push-4{left:33.33333333333333%}\n\t.col-md-push-3{left:25%}\n\t.col-md-push-2{left:16.666666666666664%}\n\t.col-md-push-1{left:8.333333333333332%}\n\t.col-md-push-0{left:0}\n\t.col-md-offset-12{margin-left:100%}\n\t.col-md-offset-11{margin-left:91.66666666666666%}\n\t.col-md-offset-10{margin-left:83.33333333333334%}\n\t.col-md-offset-9{margin-left:75%}\n\t.col-md-offset-8{margin-left:66.66666666666666%}\n\t.col-md-offset-7{margin-left:58.333333333333336%}\n\t.col-md-offset-6{margin-left:50%}\n\t.col-md-offset-5{margin-left:41.66666666666667%}\n\t.col-md-offset-4{margin-left:33.33333333333333%}\n\t.col-md-offset-3{margin-left:25%}\n\t.col-md-offset-2{margin-left:16.666666666666664%}\n\t.col-md-offset-1{margin-left:8.333333333333332%}\n\t.col-md-offset-0{margin-left:0}\n}\n@media(min-width:1200px){\n\t.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}\n\t.col-lg-12{width:100%}\n\t.col-lg-11{width:91.66666666666666%}\n\t.col-lg-10{width:83.33333333333334%}\n\t.col-lg-9{width:75%}\n\t.col-lg-8{width:66.66666666666666%}\n\t.col-lg-7{width:58.333333333333336%}\n\t.col-lg-6{width:50%}\n\t.col-lg-5{width:41.66666666666667%}\n\t.col-lg-4{width:33.33333333333333%}\n\t.col-lg-3{width:25%}\n\t.col-lg-2{width:16.666666666666664%}\n\t.col-lg-1{width:8.333333333333332%}\n\t.col-lg-pull-12{right:100%}\n\t.col-lg-pull-11{right:91.66666666666666%}\n\t.col-lg-pull-10{right:83.33333333333334%}\n\t.col-lg-pull-9{right:75%}\n\t.col-lg-pull-8{right:66.66666666666666%}\n\t.col-lg-pull-7{right:58.333333333333336%}\n\t.col-lg-pull-6{right:50%}\n\t.col-lg-pull-5{right:41.66666666666667%}\n\t.col-lg-pull-4{right:33.33333333333333%}\n\t.col-lg-pull-3{right:25%}\n\t.col-lg-pull-2{right:16.666666666666664%}\n\t.col-lg-pull-1{right:8.333333333333332%}\n\t.col-lg-pull-0{right:0}\n\t.col-lg-push-12{left:100%}\n\t.col-lg-push-11{left:91.66666666666666%}\n\t.col-lg-push-10{left:83.33333333333334%}\n\t.col-lg-push-9{left:75%}\n\t.col-lg-push-8{left:66.66666666666666%}\n\t.col-lg-push-7{left:58.333333333333336%}\n\t.col-lg-push-6{left:50%}\n\t.col-lg-push-5{left:41.66666666666667%}\n\t.col-lg-push-4{left:33.33333333333333%}\n\t.col-lg-push-3{left:25%}\n\t.col-lg-push-2{left:16.666666666666664%}\n\t.col-lg-push-1{left:8.333333333333332%}\n\t.col-lg-push-0{left:0}\n\t.col-lg-offset-12{margin-left:100%}\n\t.col-lg-offset-11{margin-left:91.66666666666666%}\n\t.col-lg-offset-10{margin-left:83.33333333333334%}\n\t.col-lg-offset-9{margin-left:75%}\n\t.col-lg-offset-8{margin-left:66.66666666666666%}\n\t.col-lg-offset-7{margin-left:58.333333333333336%}\n\t.col-lg-offset-6{margin-left:50%}\n\t.col-lg-offset-5{margin-left:41.66666666666667%}\n\t.col-lg-offset-4{margin-left:33.33333333333333%}\n\t.col-lg-offset-3{margin-left:25%}\n\t.col-lg-offset-2{margin-left:16.666666666666664%}\n\t.col-lg-offset-1{margin-left:8.333333333333332%}\n\t.col-lg-offset-0{margin-left:0}\n}\n/*2.2 响应式隐藏显示\n\tName:\t\t\tstyle_Layout\n\tExplain:\t\t左右两栏|左中右三栏|上中下\n\tLast Modify:\tguojunhui\n*/\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg,\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@media ( max-width : 767px) {\n\t.visible-xs {display: block !important}\n\ttable.visible-xs {display: table}\n\ttr.visible-xs {display: table-row !important}\n\tth.visible-xs,td.visible-xs {display: table-cell !important}\n\t.hidden-xs {display: none !important}\n\t.visible-xs-block {display: block !important}\n\t.visible-xs-inline {display: inline !important}\n\t.visible-xs-inline-block {display: inline-block !important}\n}\n@media ( min-width : 768px) and (max-width: 991px) {\n\t.visible-sm {display: block !important}\n\ttable.visible-sm {display: table}\n\ttr.visible-sm {display: table-row !important}\n\tth.visible-sm,td.visible-sm {display: table-cell !important}\n\t.hidden-sm {display: none !important}\n\t.visible-sm-block {display: block !important}\n\t.visible-sm-inline {display: inline !important}\n\t.visible-sm-inline-block {display: inline-block !important}\n}\n@media ( min-width : 992px) and (max-width: 1199px) {\n\t.visible-md {display: block !important}\n\ttable.visible-md {display: table}\n\ttr.visible-md {display: table-row !important}\n\tth.visible-md,td.visible-md {display: table-cell !important}\n\t.hidden-md {display: none !important}\n\t.visible-md-block {display: block !important}\n\t.visible-md-inline {display: inline !important}\n\t.visible-md-inline-block {display: inline-block !important}\n}\n@media ( min-width : 1200px) {\n\t.visible-lg {display: block !important}\n\ttable.visible-lg {display: table}\n\ttr.visible-lg {display: table-row !important}\n\tth.visible-lg,td.visible-lg {display: table-cell !important}\n\t.hidden-lg {display: none !important}\n\t.visible-lg-block {display: block !important}\n\t.visible-lg-inline {display: inline !important}\n\t.visible-lg-inline-block {display: inline-block !important}\n}\n\n.visible-print {display: none !important}\n.visible-print-block {display: none !important}\n.visible-print-inline {display: none !important}\n.visible-print-inline-block {display: none !important}\n@media print {\n\t.visible-print {display: block !important}\n\ttable.visible-print {display: table}\n\ttr.visible-print {display: table-row !important}\n\tth.visible-print,td.visible-print {display: table-cell !important}\n\t.visible-print-block {display: block !important}\n\t.visible-print-inline {display: inline !important}\n\t.visible-print-inline-block {display: inline-block !important}\n\t.hidden-print {display: none !important}\n}\n/*最外层*/\n.containBox {background-color:#fff;position:relative;z-index:100;zoom:1;-moz-transition:-moz-transform .2s ease-out;-webkit-transition:-webkit-transform .2s ease-out;-o-transition:-o-transform .2s ease-out;transition:transform .2s ease-out;top:0px;}\n.sideBox {display:none}\n\t.containBox-bg{ display: none}\n@media (max-width:767px) {\n    body,.content {font-size:16px;line-height:1.6}\n\thtml,body{height: 100%}\n\t.containBox{ position:fixed; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden;\n\t}\n\t\t.containBox-bg{position:fixed;width:100%;top:0;left:0; display: block;z-index:2000}\n    /*隐藏的菜单*/\n    .sideBox {position:absolute;display:block;z-index:99;right:0;top:0;bottom:0;width:250px;background-color:#303135}\n    .sideBox .navbar-nav {display:block}\n    .sideBox .navbar-nav li {border-bottom:1px solid #222;display:block}\n    .sideBox .navbar-nav a {color:#fff;display:block;padding-left:20px;padding:10px 30px;}\n    .sideBox .navbar-nav a:hover {text-decoration:none;}\n    .Hui-wraper {width:auto;padding:0 10px}\n    .AD-img img {width:100%;height:auto}\n\tbody.sideBox-open .containBox{\n\t\t\t-moz-transform: translate3d(-250px,0,0);\n\t\t-webkit-transform: translate3d(-250px,0,0);\n\t\t\t\ttransform: translate3d(-250px,0,0);\n\t\t\t\tbackface-visibility: hidden;\n\t\t-webkit-backface-visibility: hidden;\n\t\t\t-moz-backface-visibility: hidden;\n\t\t\t-ms-backface-visibility: hidden;\n\t}\n\t.wap-container{ height: 100%;width: 100%;min-width: 320px;overflow: auto;}\n\tbody.sideBox-open .containBox-bg{bottom:0;right:0;}\n}\n/*2.3 常用布局\n\tName:\t\t\tstyle_Layout\n\tExplain:\t\t左右两栏|左中右三栏|上中下\n\tLast Modify:\tguojunhui\n*/\n.Hui-wraper,.wp{margin-left:auto;margin-right:auto;text-align:left}\n.sd{float:right}\n.ct2 .mn{float:left}\n.ct2 .sd{float:right}\n.ct2_r .leftmenu{float:left}\n.ct2_r .mn{float:right}\n.ct3 .app{float:left;margin-right:20px}\n.ct3 .mn{float:left;border-left:solid 1px #ddd}\n.ct3 .sd{float:right}\n.w-1000{width:1000px}\n.w-980{width:980px}\n.w-300{width:300px}\n.w-200{width:200px}\n@media (max-width: 1000px) {\n\t.Hui-wraper,.wp,{ width:auto!important;padding:0 15px!important}\n}\n@media print{\n\t.Hui-wraper{width:auto}\n}\n/*3.0 基础样式*/\n/*3.1 排版*/\n/*3.1.1 标题\n\tExample：\n\t<h1>h1. 大标题<small>小标题</small></h1>\n    <h2>h2. 大标题<small>小标题</small></h2>\n    <h3>h3. 大标题<small>小标题</small></h3>\n    <h4>h4. 大标题<small>小标题</small></h4>\n    <h5>h5. 大标题<small>小标题</small></h5>\n    <h6>h6. 大标题<small>小标题</small></h6>\n*/\nh1,h2,h3,h4,h5,h6{font-weight:500;line-height:1.1;color:inherit}\nh1 small,h2 small,h3 small,h4 small,h5 small,h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small{font-weight:400;line-height:1;color:#999}\nh1,h2,h3{padding-top:20px;padding-bottom:10px}\nh1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}\nh4,h5,h6{margin-top:10px;margin-bottom:10px}\nh4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}\nh1{font-size:36px}\nh2{font-size:30px}\nh3{font-size:24px}\nh4{font-size:18px}\nh5{font-size:14px}\nh6{font-size:12px}\n\n/*3.1.2 强调\n\tExample:\n\t<p>这是段落，向下10像素间距</p>\n\t<smail>小型文本，是父容器字体大小的85%</smail>\n\t<strong>重要文本，加粗显示</strong>\n\t<em>被强调的文本，斜体显示</em>\n\t<u>带下划线的文本</u>\n\t<cite>引用</cite>\n\t<mark>突出显示文本</mark>\n\t<del>带删除线的文本</del>\n\t<pre class=\"prettyprint linenums\">预格式化的文本</pre>\n*/\np{margin-bottom:10px}\t/*段落*/\nsmall{font-size:85%}\t/*小型文本*/\nb,strong {font-weight: bold}\t/*重要的文本，加粗*/\nem{font-style:italic}\t/*被强调的文本*/\ni{}\t/*斜体*/\nu{}\t/*加下划线*/\ncite{font-style:normal}\t/*引用*/\nmark{color:#000;background:#ff0}/*突出显示文本*/\nvar{}\t/*变量*/\nkbd{}\t/*键盘文本*/\ncode{}\t/*计算机代码文本*/\ndfn{font-style: italic}\t/*一个定义项目*/\ndel{}\t/*删除线*/\ncode,kbd,pre,samp {font-family: monospace, serif;font-size: 1em}\npre{white-space: pre-wrap}\t/*预格式化的文本*/\n.uppercase{text-transform:uppercase} /*文字大写*/\n.lowercase{text-transform:lowercase} /*文字小写*/\n.capitalize{text-transform:capitalize} /*首字母大写*/\n.en{font-family:Arial!important}\n/*3.1.3 对齐\n\tName:\t\t\tstyle_text-align\n\tExample:\t\tclass=\"text-l|text-r|text-c|va-t|va-m|va-b\"\n\tExplain:\t\t.text-水平对齐 （.text-l左对齐|.text-r右对齐|.text-c居中对齐）\n\t\t\t\t\t.va-上下对齐 （.va-t 居上对齐|.va-m 居中对齐|.va-b 居下对齐）\n*/\n.text-l{text-align:left}.text-r{text-align:right}.text-c{text-align:center}\n.va *{vertical-align:sub!important;*vertical-align:middle!important;_vertical-align:middle!important}\n.va-t{vertical-align:top!important}.va-m{vertical-align:middle!important}.va-b{vertical-align:bottom!important}\n/*3.1.4 定位\n\tName:\t\t\tstyle_position\n\tExample:\t\tclass=\"pos-r|pos-a|pos-f\"\n\tExplain:\t\t.pos-r 相对定位|.pos-a 绝对定位|.pos-f 固定\n*/\n.pos-r{position:relative}.pos-a{position:absolute}.pos-f{position:fixed}\n/*3.1.5 浮动\n\tName:\t\t\tstyle_float\n\tExample:\t\tclass=\"l|r\"\n\tExplain:\t\t.l 左浮动|.r 右浮动\n*/\n.l,.f-l{float:left!important;_display:inline}\n.r,.f-r{float:right!important;_display:inline}\n\n[class*=\"span\"].r,\n[class*=\"span\"].f-r{float:right}\n\n/*控制元素对定位的位置：居左|居右|j居上|居下*/\n.pos-left{left:0; right:auto}\n.pos-right{right:0; left:auto}\n.pos-top{top:0; bottom:auto}\n.pos-bottom{top:auto; bottom:0}\n\n/*3.1.6 文字单行溢出省略号\n\tName:\t\t\tstyle_text-overflow\n\tExample:\t\tclass=\"text-overflow\"\n*/\n.text-overflow{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n/*3.1.7 线条\n\tName:\t\t\tstyle_line\n\tExample:\t\tclass=\"line\"\n*/\n.line{font-size:0; line-height:0; border-top: solid 1px #eee; float: none}\n/*3.1.8 外边距\n\tName:\t\t\tstyle_margin\n\tExample:\t\tclass=\"mt-5|mt-10...\"\n\tExplain:\t\t.mt表示上边距|.mb表示下边距|.ml表示左边距|.mr表示右边距\n*/\n.mt-5{margin-top:5px}.mt-10{margin-top:10px}.mt-15{margin-top:15px}.mt-20{margin-top:20px}.mt-25{margin-top:25px}.mt-30{margin-top:30px}.mt-35{margin-top:35px}.mt-40{margin-top:40px}.mt-50{margin-top:50px}\n.mb-5{margin-bottom:5px}.mb-10{margin-bottom:10px}.mb-15{margin-bottom:15px}.mb-20{margin-bottom:20px}.mb-30{margin-bottom:30px}.mb-40{margin-bottom:40px}.mb-50{margin-bottom:50px}\n.ml-5{margin-left:5px}.ml-10{margin-left:10px}.ml-15{margin-left:15px}.ml-20{margin-left:20px}.ml-30{margin-left:30px}.ml-40{margin-left:40px}.ml-50{margin-left:50px}\n.mr-5{margin-right:5px}.mr-10{margin-right:10px}.mr-15{margin-right:15px}.mr-20{margin-right:20px}.mr-30{margin-right:30px}.mr-40{margin-right:40px}.mr-50{margin-right:50px}\n/*3.1.9 内填充\n\tName:\t\t\tstyle_padding\n\tExample:\t\tclass=\"pt-5|pt-10|……\"\n\tExplain:\t\t.pt表示上填充|.pb表示下填充|.pl表示左填充|.pr表示右填充\n*/\n.pt-5{padding-top:5px}.pt-10{padding-top:10px}.pt-15{padding-top:15px}.pt-20{padding-top:20px}.pt-25{padding-top:25px}.pt-30{padding-top:30px}\n.pb-5{padding-bottom:5px}.pb-10{padding-bottom:10px}.pb-15{padding-bottom:15px}.pb-20{padding-bottom:20px}.pb-25{padding-bottom:25px}.pb-30{padding-bottom:30px}\n.pl-5{padding-left:5px}.pl-10{padding-left:10px}.pl-15{padding-left:15px}.pl-20{padding-left:20px}.pl-25{padding-left:25px}.pl-30{padding-left:30px}\n.pr-5{padding-right:5px}.pr-10{padding-right:10px}.pr-15{padding-right:15px}.pr-20{padding-right:20px}.pr-25{padding-right:25px}.pr-30{padding-right:30px}\n.pd-5{padding:5px}.pd-10{padding:10px}.pd-15{padding:15px}.pd-20{padding:20px}.pd-25{padding:25px}.pd-30{padding:30px}.pd-40{padding:40px}\n/*3.1.10 边框，css3圆角\n\tName:\t\t\tstyle-border\n\tExample:\t\tclass=\"bk_gray radius\"\n\tExplain:\t\t.bk_gray 边框|radius 圆角|round 椭圆 | circle 圆形\n*/\n.bk-gray{border:solid 1px #eee}\n.radius{border-radius:4px}\n.size-MINI.radius{ border-radius:3px}\n.size-L.radius{ border-radius:5px}\n.size-XL.radius{ border-radius:6px}\n.round{border-radius:50%; overflow:hidden}\n\n/*3.1.11 css3阴影\n\tName:\t\t\tstyle_shadow\n\tExample:\t\tclass=\"box_shadow|text-shadow\"\n\tExplain:\t\tbox_shadow 块级元素阴影，全局样式，可用在表格，文本框，文本域，div等块级元素上。\n\t\t\t\t\ttext-shadow 文字阴影\n*/\n.box-shadow{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.1);box-shadow:0 1px 2px rgba(0,0,0,0.1)}\n.text-shadow{-webkit-text-shadow:0 0 2px rgba(0,0,0,0.2);text-shadow:0 0 2px rgba(0,0,0,0.2)}\n/*3.1.12 行内分割竖线\n\tName:\t\t\tstyle_pipe\n\tExample:\t\t<span class=\"pipe\">|</span>\n*/\n.pipe{margin:0 5px;color:#CCC;font-size:10px!important}\n/*3.1.13 文字尺寸\n\tName:\t\t\tstyle_font-size\n\tExample:\t\tclass=\"f-12|f-14|f-16|f-18|f-20|f-24|f-26|f-28|f-30\"\n\tExplain:\t\t12px字体|14px字体|16px字体|18px字体|20px字体|24px字体|26px字体|28px字体|30px字体\n*/\n.f-12{font-size:12px}.f-14{font-size:14px}.f-16{font-size:16px}.f-18{font-size:18px}.f-20{font-size:20px}.f-22 { font-size: 22px }.f-24{font-size:24px}.f-26{font-size:26px}.f-28{font-size:28px}.f-30{font-size:30px}\n/*3.1.14 文字行距\n\tName:\t\t\tmod_line-height\n\tExample:\t\tclass=\"lh-16|lh-18|lh-20|lh-22|lh-24|lh-26|lh-28|lh-30\"\n\tExplain:\t\t16px行高|18px行高|20px行高|22px行高|24px行高|26px行高|30px行高\n*/\n.lh-16{line-height:16px}.lh-18{line-height:18px}.lh-20{line-height:20px}.lh-22{line-height:22px}.lh-24{line-height:24px}.lh-26{line-height:26px}.lh-28{line-height:28px}.lh-30{line-height:30px}\n/*2.0以前的兼容版本*/\n.l16{line-height:16px}.l18{line-height:18px}.l20{line-height:20px}.l22{line-height:22px}.l-24{line-height:24px}.l-26{line-height:26px}.l-28{line-height:28px}.l-30{line-height:30px}\n\n/*3.1.15 文字颜色\n\tName:\t\t\tstyle_color\n\tExample:\t\tclass=\"c-primary|c-sub|c-success|c-danger|c-warning|c-333|c-666|c-999|c-red|c-green|c-blue|c-white|c-black|c-orange\"\n\tExplain:\t\t主要颜色|次主色|强调色—成功|强调色—危险|强调色—警告色|强调色—错误色|次主色—浅黑|辅助色—灰色|标准色—红色|标准色—绿色|标准色—蓝色|标准色—白色|标准色—黑色|标准色—橙色\n*/\n/*全局默认链接颜色*/\nbody{ background-color:#fff; color:#333}\n.bg-fff{ background-color:#fff}\na{color:#333}\na:hover,.active a{color:#06c}\n\n/*主要颜色*/\n.c-primary,.c-primary a,a.c-primary{color:#5a98de}\n.c-primary a:hover,a.c-primary:hover{ color:#5a98de}\n/*次主色*/\n.c-secondary,.c-secondary a,a.c-secondary{color:#555}\n.c-secondary a:hover,a.c-secondary:hover{ color:#555}\n\n/*强调色—成功*/\n.c-success,.c-success a,a.c-success{color:#5eb95e}\n.c-success a:hover,a.c-success:hover{ color:#5eb95e}\n\n/*强调色—危险*/\n.c-danger,.c-danger a,a.c-danger{color:#dd514c}\n.c-danger a:hover,a.c-danger:hover{ color:#dd514c}\n\n/*强调色—警告*/\n.c-warning,.c-warning a,a.c-warning{color:#f37b1d}\n.c-warning a:hover,a.c-warning:hover{ color:#f37b1d}\n\n/*强调色—错误*/\n.c-error,.c-error a,a.c-error{color:#c00}\n.c-error a:hover,a.c-error:hover{ color:#c00}\n\n/*辅助色—浅黑*/\n.c-333,.c-333 a,a.c-333{color:#333}\n.c-333 a:hover,a.c-333:hover{ color:#333}\n\n/*辅助色—灰色*/\n.c-666,.c-666 a,a.c-666{color:#666}\n.c-666 a:hover,a.c-666:hover{ color:#666}\n.c-999,.c-999 a,a.c-999{color:#999}\n.c-999 a:hover,a.c-999:hover{color:#999}\n\n/*标准色—红色*/\n.c-red,.c-red a,a.c-red{color:red}\n.c-red a:hover,a.c-red:hover{ color:red}\n/*标准色—绿色*/\n.c-green,.c-green a,a.c-green{color:green}\n.c-red a:hover,a.c-red:hover{color:green}\n/*标准色—蓝色*/\n.c-blue,.c-blue a,a.c-blue{color:blue}\n.c-blue a:hover,a.c-blue:hover{color:blue}\n/*标准色—白色*/\n.c-white,.c-white a,a.c-white{color:white}\n.c-white a:hover,a.c-white:hover{color:white}\n/*标准色—黑色*/\n.c-black,.c-black a{color:black}\n.c-black a:hover,a.c-black:hover{color:black}\n/*标准色—橙色*/\n.c-orange,.c-orange a,a.c-orange{color:orange}\n.c-orange a:hover,a.c-orange:hover{color:orange}\n\n/*3.1.16 文字颜色强调\t从2.0起废弃3.1.16 文字强调，字体颜色全部放入到3.1.15\n\tExample:\t\tclass=\"text-muted|text-primary|text-warning|text-error|text-danger|text-success|text-info\"\n\tExplain:\t\t柔和|重要|警告|错误|危险|成功|信息\n*/\n\n\n/*3.1.17 缩略语\n\tExample:\t\t<abbr title=\"User Interface\" class=\"initialism\">UI</abbr>\n\tExplain:\n*/\nabbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}\nabbr.initialism{font-size:90%;text-transform:uppercase}\n/*3.1.18 地址\n\tExample:\t\t<address>北京市海淀区上地……</address>\n\tExplain:\n*/\naddress{display:block;margin-bottom:20px;font-style:normal;line-height:20px}\n/*3.1.19 引用\n\tExample:\t\t<blockquote>这是引用的内容</blockquote>\n\tExplain:\n*/\nblockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}\nblockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}\nblockquote small{display:block;line-height:20px;color:#999}\nblockquote small:before{content:'\\2014 \\00A0'}\nblockquote.text-r{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}\nblockquote.text-r p,blockquote.text-r small{text-align:right}\nblockquote.text-r small:before{content:''}\nblockquote.text-r small:after{content:'\\00A0 \\2014'}\nq:before,q:after,blockquote:before,blockquote:after{content:\"\"}\nq {/*短的引用*/quotes: \"\\201C\" \"\\201D\" \"\\2018\" \"\\2019\"}\n/*3.1.20 上标，下标\n\tExample:\t\t<sup>2</sup>\t<sub>2<sub>\n\tExplain:\t\t上标|下标\n*/\nsub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}\nsup{top:-0.5em}sub{bottom:-0.25em}\n/*3.1.21 内容样式\n\tName:\t\t\tstyle_content\n\tExample:\t\t<div class=\"content\"><p>……</p></div>\n\tExplain:\t\t内容样式\n*/\n.content{position:relative;font-size:17px;line-height:1.8;overflow:hidden;text-align:left;word-break: break-all;word-wrap: break-word}\n.content h3{font-size:18px}\n.content h4{font-size:16px}\n.content p{margin-bottom: 1.5rem;text-align: justify;word-break:break-all}\n.content p.text-c{ text-align:center}\n\t.indent{ text-indent:2em}\n.content img{max-width:100%}\n.content ul{text-indent:2em}\n@media (max-width: 767px) {\n\t.content{ font-size:16px}\n}\n@media (max-width: 480px) {\n\t.content img{max-width:100%!important; height:auto!important;width:expression(this.width > 320 ? \"320px\" : this.width)!important}\n\t*html .content img{width:expression(this.width>320&&this.width>this.height?320:auto)}\n}\n/*3.1.22 列表\n\tName:\t\t\tstyle_ulolli\n\tExample:\n<ul class=\"list-view\">\n\t<li class=\"item\">无序列表</li>\n\t<li class=\"item\">无序列表</li>\n\t<li class=\"item\">无序列表</li>\n</ul>\n<ol class=\"list-view\">\n\t<li class=\"item\">无序列表</li>\n\t<li class=\"item\">无序列表</li>\n\t<li class=\"item\">无序列表</li>\n</ol>\n\tExplain:\n*/\nul.unstyled,ol.unstyled{margin-left:0;list-style:none}\nul.inline,ol.inline{margin-left:0;list-style:none}\nul.inline > li,ol.inline > li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}\n.list-view > .item{ padding:10px; position:relative; overflow:hidden}/*禁止换行*/\n.list-view > .item .date{font-size:12px; font-family:Arial; color:#999}\n/*横向手机 竖向平板*/\n@media (max-width: 767px) {\n\t.list-view > .item{ font-size:18px; padding:11px 15px;border-bottom: 1px solid #eee}\n\t.list-view > .item > a{display:block; margin:-11px -15px}\n\t.night .list-view > .item{border-bottom: 1px solid #1F1F1F}\n\t.list-view > .item .date{display:none}\n\t.list-view > .item .Hui-iconfont {background-size:9px auto;margin-top:-7px;position: absolute;right:15px;top: 50%}\n}\n\n/*排行榜*/\n/*<ol class=\"list-view list-top\"><li class=\"item\"><em class=\"num\">1</em><a href=\"#\">排行榜列表</a><span class=\"date\">12</span></li></ol>*/\n.list-top > .item{padding-left: 30px}\n.list-top > .item .num{ position:absolute; top:11px; display:block; width:20px; height:20px; color:#fff; background-color:#5a98de; text-align:center}\n\n/*3.1.23 描述\n\tName:\t\t\tstyle_dldtdd\n\tExample:\t\t<dl class=\"dl-horizontal cl\"><dt>H-ui</dt><dd>基于Bootstrap框架的改进扩展的前端框架</dd></dl>\n\tExplain:\t\t.dl-horizontal 水平描述，默认不加为垂直模式。\n*/\n.dl-horizontal.cl{}\n.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}\n.dl-horizontal dd{margin-left:180px}\n/*3.1.24 隐藏 显示\n  Name:\t\t\t\tstyle_display\n  Example:    <div class=\"hide\">隐藏的内容</div> <div class=\"show\">显示的内容</div>\n  Explain:    \t\t.hide 隐藏 / .show 显示\n*/\n.hide{display:none}[hidden]{display: none}\n.hidden{display:none!important;visibility:hidden!important}\n.f-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}\n[class*=\"span\"].hide,.row-fluid [class*=\"span\"].hide{display:none}\n.show{display:block}\n.invisible{visibility:hidden}\n\n/*3.1.25 尺寸\t新增尺寸全局类名，用于表单、按钮、表格、头像、标签等元素上，要与元素一起配合使用，方能看到效果*/\n.size-MINI{}/*迷你*/\n.size-S{}/*小*/\n.size-M{}/*中 缺省默认尺寸，可以不写，可以理解为：均码*/\n.size-L{}/*L*/\n.size-XL{}/*大*/\n.size-XXL{}/*加大*/\n.size-XXXL{}/*超大*/\n\n.input-text,.btn,.input-text.size-M,.btn.size-M{ font-size:14px; height:31px;*height:auto;line-height:1.42857;padding:4px}/*默认为M，可以不写，可以理解为：均码*/\na.btn,a.btn.size-M,span.btn,span.btn.size-M{ line-height:21px}\n.btn,.btn.size-M{ padding:4px 12px}\n\n.input-text.size-MINI,.btn.size-MINI{font-size:12px; height:23px;padding:1px 2px;line-height:1.42857}/*迷你*/\na.btn.size-MINI,span.btn.size-MINI{ line-height:21px}\n.btn.size-MINI{ padding:1px 4px}\n\n.input-text.size-S,.btn.size-S{font-size:12px; height:27px;padding:3px;line-height:1.42857}/*小*/\na.btn.size-S,span.btn.size-S{ line-height:19px}\n.btn.size-S{ padding:3px 8px}\n\n.input-text.size-L,.btn.size-L{font-size:16px; height:41px; padding:8px}/*大*/\na.btn.size-L,span.btn.size-L{ line-height:23px}\n.btn.size-L{ padding:8px 16px}\n\n.input-text.size-XL,.btn.size-XL{font-size:18px; height:48px; padding:10px}/*特大*/\na.btn.size-XL,span.btn.size-XL{ line-height:26px}\n.btn.size-XL{ padding:10px 24px}\n\n@media (max-width: 767px) {\n\t.responsive .input-text.size-MINI,.responsive .btn.size-MINI{height:24px}\n\t.responsive .input-text.size-S,.responsive .btn.size-S{ font-size:14px; height:30px}\n\t.responsive .input-text,.btn,.responsive .input-text.size-M,.responsive .btn.size-M{ font-size:16px; height:36px}\n\t.responsive .input-text.size-L,.responsive .btn.size-L{ font-size:18px; height:42px}\n\t.responsive .input-text.size-XL,.responsive .btn.size-XL{ font-size:20px; height:48px}\n}\n\n/*3.2 代码\n\tName:\t\t\tstyle_pre\n\n\tExample:\t\t<code></code>,<pre class=\"prettyprint linenums\">转义过的代码</pre>\n\tExplain:\t\tcode：行内代码，pre：基本代码块;包装代码片段，.prettyprint颜色增强/.linenums显示行号\n*/\ncode{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,\"Courier New\",monospace}\npre .title,pre .keyword,pre .body,pre .des{color:#333}/*关键词*/\n\npre{display:block;font-family:Monaco,Menlo,Consolas,\"Courier New\",monospace;padding:9.5px;margin-bottom:10px;font-size:12px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px;color:#333}\n.prettyprint{margin-bottom:20px;padding:8px;background-color:#f7f7f9;border:1px solid #e1e1e8}\n.prettyprint .com { color: #998;font-style:italic }/*注释*/\n.prettyprint .tag{color:#007}/*标签*/\n.prettyprint .lit { color: #195f91}\n.prettyprint .pun,.prettyprint .opn,.prettyprint .clo { color: #93a1a1}/*等于*/\n.prettyprint .fun { color: #dc322f}\n.prettyprint .str,.prettyprint .atv { color: #D14}/*值*/\n.prettyprint .kwd,.prettyprint .prettyprint .tag { color: #1e347b}\n.prettyprint .typ,.prettyprint .atn,.prettyprint .dec,.prettyprint .var { color: teal}/*文档声明，属性*/\n.prettyprint .pln { color: #48484c}\n\n.prettyprint.linenums{box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0}\n.pre-scrollable{max-height:340px;overflow-y:scroll}\nol.linenums{list-style:decimal outside none; margin-left:20px}\nol.linenums li{ line-height:28px; padding-left:10px}\npre ol.linenums{margin:0 0 0 33px}\npre ol.linenums li{padding-left:12px;color:#bbb;line-height:18px;text-shadow:0 1px 0 #fff}\n\n@media (max-width: 767px) {\n\tpre ol.linenums{ margin-left:0; list-style:none}\n\tol.linenums li{ padding-left:0}\n\t.prettyprint.linenums{box-shadow:inset 0px 0 0 #fbfbfc,inset 0px 0 0 #ececf0}\n}\n\n/*3.3 表格\n\tName:\t\t\tstyle_table\n\tExample:\t\t<table class=\"table table-bordered table-striped table-condensed\"><thead><tr><th>…</th></tr></thead><tbody><tr><td>…</td></tr></tbody></table>\n\tExplain:\t\t表格，None无样式，仅仅有列和行|.table行与行之间以水平线相隔|.table-bordered表格外围均有外边框|.table-striped奇数行背景设为浅灰色|.table-condensed竖直方向padding缩减一半，从8px变为4px，所有的 td 和 th 元素都受影响\n*/\n/*默认table*/\ntable{width:100%;empty-cells:show;background-color:transparent;border-collapse:collapse;border-spacing:0}\ntable th{text-align:left; font-weight:400}\n/*带水平线*/\n.table th{font-weight:bold}\n.table th,.table td{padding:8px;line-height:20px;word-break:break-all}\n.table td{text-align:left}\n.table tbody tr.success > td{background-color:#dff0d8}\n.table tbody tr.error > td{background-color:#f2dede}\n.table tbody tr.warning > td{background-color:#fcf8e3}\n.table tbody tr.info > td{background-color:#d9edf7}\n.table tbody + tbody{border-top:2px solid #ddd}\n.table .table{background-color:#fff}\n\n/*带横向分割线*/\n.table-border{border-top:1px solid #ddd}\n.table-border th,.table-border td{border-bottom:1px solid #ddd}\n\n/*th带背景*/\n.table-bg thead th{background-color:#F5FAFE}\n/*带外边框*/\n.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0}\n.table-bordered th,.table-bordered td{border-left:1px solid #ddd}\n.table-border.table-bordered{border-bottom:0}\n\n/*奇数行背景设为浅灰色*/\n.table-striped tbody > tr:nth-child(odd) > td,\n.table-striped tbody > tr:nth-child(odd) > th{background-color:#f9f9f9}\n/*竖直方向padding缩减一半*/\n.table-condensed th,\n.table-condensed td{padding:4px 5px}\n/*鼠标悬停样式*/\n.table-hover tbody tr:hover td,\n.table-hover tbody tr:hover th{background-color: #f5f5f5}\n/*鼠标选择整行样式*/\n.table tbody tr.selected td{background-color:#F3F3F3}\n/*定义颜色*/\n/*悬停在行*/\n.table tbody tr.active,\n.table tbody tr.active > td,\n.table tbody tr.active > th,\n.table tbody tr .active{ background-color:#F5F5F5!important}\n/*成功或积极*/\n.table tbody tr.success,\n.table tbody tr.success > td,\n.table tbody tr.success > th,\n.table tbody tr .success{background-color:#DFF0D8!important}\n\n/*警告或出错*/\n.table tbody tr.warning,\n.table tbody tr.warning > td,\n.table tbody tr.warning > th,\n.table tbody tr .warning{background-color:#FCF8E3!important}\n/*危险*/\n.table tbody tr.danger,\n.table tbody tr.danger > td,\n.table tbody tr.danger > th,\n.table tbody tr .danger{background-color:#F2DEDE!important}\n\n/*表格文字对齐方式，默认是居左对齐*/\n.table .text-c th,.table .text-c td{text-align:center}/*整行居中*/\n.table .text-r th,.table .text-r td{text-align:right}/*整行居右*/\n.table th.text-l,.table td.text-l{text-align:left!important}/*单独列居左*/\n.table th.text-c,.table td.text-c{text-align:center!important}/*单独列居中*/\n.table th.text-r,.table td.text-r{text-align:right!important}/*单独列居右*/\n\n/*datatable*/\ntable.dataTable {border-collapse: separate;border-spacing: 0;clear: both}\ntable.dataTable thead .sorting_asc, table.dataTable thead .sorting_desc, table.dataTable thead .sorting {cursor: pointer; background-repeat:no-repeat;background-position:right center}\ntable.dataTable thead .sorting{background-image:url(../images/dataTable/sort_both.png)}\ntable.dataTable thead .sorting_asc {background-image:url(../images/dataTable/sort_asc.png)}\ntable.dataTable thead .sorting_desc {background-image:url(../images/dataTable/sort_desc.png)}\n.dataTable td.sorting_1 {background-color: #f5fafe}\n.dataTables_wrapper .dataTables_length {float: left;padding-bottom:20px}\n.dataTables_wrapper .dataTables_length .select{ width:50px}\n.dataTables_wrapper .dataTables_filter {float: right;text-align: right}\n.dataTables_wrapper .dataTables_filter .input-text { width:auto}\n.dataTables_wrapper .dataTables_info {clear: both;float: left;padding-top:10px;font-size:14px; color:#666}\n.dataTables_wrapper .dataTables_paginate {float: right;padding-top:10px;text-align: right}\n.dataTables_wrapper .dataTables_paginate .paginate_button {border: 1px solid #ccc;cursor: pointer;display: inline-block;margin-left: 2px;text-align: center;text-decoration: none;color: #666;height: 26px;line-height: 26px;text-decoration: none;margin: 0 0px 6px 6px;padding: 0 10px;font-size:14px}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover,\n.dataTables_wrapper .dataTables_paginate .paginate_button.current,\n.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {background:#5a98de;color:#fff}\n\n/*表格尺寸*/\n.table.size-MINI{}/*迷你*/\n.table.size-S{}/*小*/\n.table.size-M{}/*中*/\n.table.size-L{}/*默认为L，可以不写，可以理解为：均码*/\n.table.size-XL{}/*大*/\n.table.size-XXL{}/*加大*/\n.table.size-XXXL{}/*超大*/\n\n/*让表格支持响应式*/\n/*\n<div class=\"table-responsive\">\n  <table class=\"table\">\n    ...\n  </table>\n</div>\n*/\n@media (max-width: 767px) {\n\t/*.table-responsive {width: 100%;margin-bottom: 15px;overflow-x: scroll;overflow-y: hidden;border: 1px solid #ddd;-ms-overflow-style: -ms-autohiding-scrollbar;-webkit-overflow-scrolling: touch}\n\t.table-responsive > .table {margin-bottom: 0}\n\t.table-responsive > .table > thead > tr > th,\n\t.table-responsive > .table > tbody > tr > th,\n\t.table-responsive > .table > tfoot > tr > th,\n\t.table-responsive > .table > thead > tr > td,\n\t.table-responsive > .table > tbody > tr > td,\n\t.table-responsive > .table > tfoot > tr > td {white-space: nowrap}\n\t.table-responsive > .table-bordered {border: 0}\n\t.table-responsive > .table-bordered > thead > tr > th:first-child,\n\t.table-responsive > .table-bordered > tbody > tr > th:first-child,\n\t.table-responsive > .table-bordered > tfoot > tr > th:first-child,\n\t.table-responsive > .table-bordered > thead > tr > td:first-child,\n\t.table-responsive > .table-bordered > tbody > tr > td:first-child,\n\t.table-responsive > .table-bordered > tfoot > tr > td:first-child {border-left: 0}\n\t.table-responsive > .table-bordered > thead > tr > th:last-child,\n\t.table-responsive > .table-bordered > tbody > tr > th:last-child,\n\t.table-responsive > .table-bordered > tfoot > tr > th:last-child,\n\t.table-responsive > .table-bordered > thead > tr > td:last-child,\n\t.table-responsive > .table-bordered > tbody > tr > td:last-child,\n\t.table-responsive > .table-bordered > tfoot > tr > td:last-child {border-right: 0}\n\t.table-responsive > .table-bordered > tbody > tr:last-child > th,\n\t.table-responsive > .table-bordered > tfoot > tr:last-child > th,\n\t.table-responsive > .table-bordered > tbody > tr:last-child > td,\n\t.table-responsive > .table-bordered > tfoot > tr:last-child > td {border-bottom: 0}\n\t*/\n\t.table-responsive th,.table-responsive td{ display: block;width: 100%!important;box-sizing: border-box;}\n\n}\n\n/*3.4 表单\n\tName:\t\t\tstyle_form\n\tExample:\n\tExplain:\n\n*/\n/*3.4.1 input,textarea 文本域 文本区域*/\n/*默认状态*/\n.input-text,.textarea{box-sizing:border-box;border:solid 1px #ddd;width:100%;\n    -webkit-transition:all 0.2s linear 0s;\n       -moz-transition:all 0.2s linear 0s;\n         -o-transition:all 0.2s linear 0s;\n            transition:all 0.2s linear 0s}\n.textarea{ height:100px; resize:none; font-size:14px; padding:4px}\n\t.textarea-numberbar{ position:absolute; right:20px; bottom:5px; z-index:1; margin-bottom:0}\n\t.textarea-length{ font-style:normal}\n.input-text:hover,\n.textarea:hover{border: solid 1px #3bb4f2}\n/*得到焦点后*/\n.input-text.focus,\n.textarea.focus{border:solid 1px #0f9ae0 \\9;border-color:rgba(82,168,236,0.8);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(102, 175, 233, 0.6)}\n/*不可点击*/\n.input-text.disabled\n,.textarea.disabled,\n.input-text.disabled.focus,\n.textarea.disabled.focus{background-color:#ededed; cursor:default;border-color: #ddd;\n\t-webkit-box-shadow:inset 0 2px 2px #e8e7e7;\n       -moz-box-shadow:inset 0 2px 2px #e8e7e7;\n            box-shadow:inset 0 2px 2px #e8e7e7}\n/*只读状态*/\n.input-text.disabled,\n.textarea.disabled{background-color:#e6e6e6; cursor:default}\n/*阴影*/\n.input-text.box-shadow,\n.textarea.box-shadow{-ms-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}\n/*行内元素*/\n.input-text.inline{ display:inline-block; width:auto}\n\n/*3.4.2 checkbox radio  单选 多选\n\tExample:\n<div class=\"skin-minimal\">\n  <div class=\"check-box\">\n    <input type=\"checkbox\" id=\"checkbox-1\">\n    <label for=\"checkbox-1\">复选框</label>\n  </div>\n</div>\n\n<div class=\"skin-minimal\">\n  <div class=\"radio-box\">\n    <input type=\"radio\" id=\"minimal-radio-1\" name=\"demo-radio1\">\n    <label for=\"minimal-radio-1\">单选按钮</label>\n  </div>\n</div>\n\tExplain:\n*/\n\ninput[type=\"radio\"],input[type=\"checkbox\"] {line-height: normal; margin-top:-4px}\n.check-box,.radio-box{ display:inline-block; box-sizing:border-box; cursor:pointer; position:relative; padding-left:30px; padding-right:20px}\n.icheckbox,\n.icheckbox-red,\n.icheckbox-green,\n.icheckbox-blue,\n.icheckbox-aero,\n.icheckbox-grey,\n.icheckbox-orange,\n.icheckbox-yellow,\n.icheckbox-pink,\n.icheckbox-purple,\n.iradio,\n.iradio-red,\n.iradio-green,\n.iradio-blue,\n.iradio-aero,\n.iradio-grey,\n.iradio-orange,\n.iradio-yellow,\n.iradio-pink,\n.iradio-purple {position: absolute;top:4px;left: 0}\n@media (max-width: 767px) {\n\t.responsive .check-box,\n\t.responsive .radio-box{ display:block}\n}\n/*3.4.2.1 jQuery.icheck.css*/\n/* iCheck.js Minimal skin\n----------------------------------- */\n.icheckbox,.iradio{display: block;margin: 0;padding: 0;width: 18px;height: 18px;background: url(../images/iCheck/minimal.png) no-repeat;border: none;cursor: pointer}\n.icheckbox,.icheckbox.static:hover{background-position: 0 0}\n.icheckbox.hover,.icheckbox:hover{background-position: -20px 0}\n.icheckbox.checked{background-position: -40px 0}\n.icheckbox.disabled{background-position: -60px 0;cursor: default}\n.icheckbox.checked.disabled{background-position: -80px 0}\n.iradio,.iradio.static:hover{background-position: -100px 0}\n.iradio.hover,.iradio:hover{background-position: -120px 0}\n.iradio.checked{background-position: -140px 0}\n.iradio.disabled{background-position: -160px 0;cursor: default}\n.iradio.checked.disabled{background-position: -180px 0}\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  only screen and (-moz-min-device-pixel-ratio: 1.5),  only screen and (-o-min-device-pixel-ratio: 1.5),  only screen and (min-device-pixel-ratio: 1.5){.icheckbox,.iradio{background-image: url(../images/iCheck/minimal@2x.png);\n\t-webkit-background-size: 200px 20px;\n\tbackground-size: 200px 20px}\n}\n/* red */\n.icheckbox-red,.iradio-red{display: block;margin: 0;padding: 0;width: 18px;height: 18px;background: url(../images/iCheck/red.png) no-repeat;border: none;cursor: pointer}\n.icheckbox-red,.icheckbox-red.static:hover{background-position: 0 0}\n.icheckbox-red.hover,.icheckbox-red:hover{background-position: -20px 0}\n.icheckbox-red.checked{background-position: -40px 0}\n.icheckbox-red.disabled{background-position: -60px 0;cursor: default}\n.icheckbox-red.checked.disabled{background-position: -80px 0}\n.iradio-red,.iradio-red.static:hover{background-position: -100px 0}\n.iradio-red.hover,.iradio-red:hover{background-position: -120px 0}\n.iradio-red.checked{background-position: -140px 0}\n.iradio-red.disabled{background-position: -160px 0;cursor: default}\n.iradio-red.checked.disabled{background-position: -180px 0}\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  only screen and (-moz-min-device-pixel-ratio: 1.5),  only screen and (-o-min-device-pixel-ratio: 1.5),  only screen and (min-device-pixel-ratio: 1.5){.icheckbox-red,.iradio-red{background-image: url(../images/iCheck/red@2x.png);\n\t-webkit-background-size: 200px 20px;\n\tbackground-size: 200px 20px}\n}\n/* green */\n.icheckbox-green,.iradio-green{display: block;margin: 0;padding: 0;width: 18px;height: 18px;background: url(../images/iCheck/green.png) no-repeat;border: none;cursor: pointer}\n.icheckbox-green,.icheckbox-green.static:hover{background-position: 0 0}\n.icheckbox-green.hover,.icheckbox-green:hover{background-position: -20px 0}\n.icheckbox-green.checked{background-position: -40px 0}\n.icheckbox-green.disabled{background-position: -60px 0;cursor: default}\n.icheckbox-green.checked.disabled{background-position: -80px 0}\n.iradio-green,.iradio-green.static:hover{background-position: -100px 0}\n.iradio-green.hover,.iradio-green:hover{background-position: -120px 0}\n.iradio-green.checked{background-position: -140px 0}\n.iradio-green.disabled{background-position: -160px 0;cursor: default}\n.iradio-green.checked.disabled{background-position: -180px 0}\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  only screen and (-moz-min-device-pixel-ratio: 1.5),  only screen and (-o-min-device-pixel-ratio: 1.5),  only screen and (min-device-pixel-ratio: 1.5){.icheckbox-green,.iradio-green{background-image: url(../images/iCheck/green@2x.png);\n\t-webkit-background-size: 200px 20px;\n\tbackground-size: 200px 20px}\n}\n/* blue */\n.icheckbox-blue,.iradio-blue{display: block;margin: 0;padding: 0;width: 18px;height: 18px;background: url(../images/iCheck/blue.png) no-repeat;border: none;cursor: pointer}\n.icheckbox-blue,.icheckbox-blue.static:hover{background-position: 0 0}\n.icheckbox-blue.hover,.icheckbox-blue:hover{background-position: -20px 0}\n.icheckbox-blue.checked{background-position: -40px 0}\n.icheckbox-blue.disabled{background-position: -60px 0;cursor: default}\n.icheckbox-blue.checked.disabled{background-position: -80px 0}\n.iradio-blue,.iradio-blue.static:hover{background-position: -100px 0}\n.iradio-blue.hover,.iradio-blue:hover{background-position: -120px 0}\n.iradio-blue.checked{background-position: -140px 0}\n.iradio-blue.disabled{background-position: -160px 0;cursor: default}\n.iradio-blue.checked.disabled{background-position: -180px 0}\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  only screen and (-moz-min-device-pixel-ratio: 1.5),  only screen and (-o-min-device-pixel-ratio: 1.5),  only screen and (min-device-pixel-ratio: 1.5){.icheckbox-blue,.iradio-blue{background-image: url(../images/iCheck/blue@2x.png);\n\t-webkit-background-size: 200px 20px;\n\tbackground-size: 200px 20px}\n}\n/* aero */\n.icheckbox-aero,.iradio-aero{display: block;margin: 0;padding: 0;width: 18px;height: 18px;background: url(../images/iCheck/aero.png) no-repeat;border: none;cursor: pointer}\n.icheckbox-aero,.icheckbox-aero.static:hover{background-position: 0 0}\n.icheckbox-aero.hover,.icheckbox-aero:hover{background-position: -20px 0}\n.icheckbox-aero.checked{background-position: -40px 0}\n.icheckbox-aero.disabled{background-position: -60px 0;cursor: default}\n.icheckbox-aero.checked.disabled{background-position: -80px 0}\n.iradio-aero,.iradio-aero.static:hover{background-position: -100px 0}\n.iradio-aero.hover,.iradio-aero:hover{background-position: -120px 0}\n.iradio-aero.checked{background-position: -140px 0}\n.iradio-aero.disabled{background-position: -160px 0;cursor: default}\n.iradio-aero.checked.disabled{background-position: -180px 0}\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  only screen and (-moz-min-device-pixel-ratio: 1.5),  only screen and (-o-min-device-pixel-ratio: 1.5),  only screen and (min-device-pixel-ratio: 1.5){.icheckbox-aero,.iradio-aero{background-image: url(../images/iCheck/aero@2x.png);\n\t-webkit-background-size: 200px 20px;\n\tbackground-size: 200px 20px}\n}\n/* grey */\n.icheckbox-grey,.iradio-grey{display: block;margin: 0;padding: 0;width: 18px;height: 18px;background: url(../images/iCheck/grey.png) no-repeat;border: none;cursor: pointer}\n.icheckbox-grey,.icheckbox-grey.static:hover{background-position: 0 0}\n.icheckbox-grey.hover,.icheckbox-grey:hover{background-position: -20px 0}\n.icheckbox-grey.checked{background-position: -40px 0}\n.icheckbox-grey.disabled{background-position: -60px 0;cursor: default}\n.icheckbox-grey.checked.disabled{background-position: -80px 0}\n.iradio-grey,.iradio-grey.static:hover{background-position: -100px 0}\n.iradio-grey.hover,.iradio-grey:hover{background-position: -120px 0}\n.iradio-grey.checked{background-position: -140px 0}\n.iradio-grey.disabled{background-position: -160px 0;cursor: default}\n.iradio-grey.checked.disabled{background-position: -180px 0}\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  only screen and (-moz-min-device-pixel-ratio: 1.5),  only screen and (-o-min-device-pixel-ratio: 1.5),  only screen and (min-device-pixel-ratio: 1.5){.icheckbox-grey,.iradio-grey{background-image: url(../images/iCheck/grey@2x.png);\n\t-webkit-background-size: 200px 20px;\n\tbackground-size: 200px 20px}\n}\n/* orange */\n.icheckbox-orange,.iradio-orange{display: block;margin: 0;padding: 0;width: 18px;height: 18px;background: url(../images/iCheck/orange.png) no-repeat;border: none;cursor: pointer}\n.icheckbox-orange,.icheckbox-orange.static:hover{background-position: 0 0}\n.icheckbox-orange.hover,.icheckbox-orange:hover{background-position: -20px 0}\n.icheckbox-orange.checked{background-position: -40px 0}\n.icheckbox-orange.disabled{background-position: -60px 0;cursor: default}\n.icheckbox-orange.checked.disabled{background-position: -80px 0}\n.iradio-orange,.iradio-orange.static:hover{background-position: -100px 0}\n.iradio-orange.hover,.iradio-orange:hover{background-position: -120px 0}\n.iradio-orange.checked{background-position: -140px 0}\n.iradio-orange.disabled{background-position: -160px 0;cursor: default}\n.iradio-orange.checked.disabled{background-position: -180px 0}\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  only screen and (-moz-min-device-pixel-ratio: 1.5),  only screen and (-o-min-device-pixel-ratio: 1.5),  only screen and (min-device-pixel-ratio: 1.5){.icheckbox-orange,.iradio-orange{background-image: url(../images/iCheck/orange@2x.png);\n\t-webkit-background-size: 200px 20px;\n\tbackground-size: 200px 20px}\n}\n/* yellow */\n.icheckbox-yellow,.iradio-yellow{display: block;margin: 0;padding: 0;width: 18px;height: 18px;background: url(../images/iCheck/yellow.png) no-repeat;border: none;cursor: pointer}\n.icheckbox-yellow,.icheckbox-yellow.static:hover{background-position: 0 0}\n.icheckbox-yellow.hover,.icheckbox-yellow:hover{background-position: -20px 0}\n.icheckbox-yellow.checked{background-position: -40px 0}\n.icheckbox-yellow.disabled{background-position: -60px 0;cursor: default}\n.icheckbox-yellow.checked.disabled{background-position: -80px 0}\n.iradio-yellow,.iradio-yellow.static:hover{background-position: -100px 0}\n.iradio-yellow.hover,.iradio-yellow:hover{background-position: -120px 0}\n.iradio-yellow.checked{background-position: -140px 0}\n.iradio-yellow.disabled{background-position: -160px 0;cursor: default}\n.iradio-yellow.checked.disabled{background-position: -180px 0}\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  only screen and (-moz-min-device-pixel-ratio: 1.5),  only screen and (-o-min-device-pixel-ratio: 1.5),  only screen and (min-device-pixel-ratio: 1.5){.icheckbox-yellow,.iradio-yellow{background-image: url(../images/iCheck/yellow@2x.png);\n\t-webkit-background-size: 200px 20px;\n\tbackground-size: 200px 20px}\n}\n/* pink */\n.icheckbox-pink,.iradio-pink{display: block;margin: 0;padding: 0;width: 18px;height: 18px;background: url(../images/iCheck/pink.png) no-repeat;border: none;cursor: pointer}\n.icheckbox-pink,.icheckbox-pink.static:hover{background-position: 0 0}\n.icheckbox-pink.hover,.icheckbox-pink:hover{background-position: -20px 0}\n.icheckbox-pink.checked{background-position: -40px 0}\n.icheckbox-pink.disabled{background-position: -60px 0;cursor: default}\n.icheckbox-pink.checked.disabled{background-position: -80px 0}\n.iradio-pink,.iradio-pink.static:hover{background-position: -100px 0}\n.iradio-pink.hover,.iradio-pink:hover{background-position: -120px 0}\n.iradio-pink.checked{background-position: -140px 0}\n.iradio-pink.disabled{background-position: -160px 0;cursor: default}\n.iradio-pink.checked.disabled{background-position: -180px 0}\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  only screen and (-moz-min-device-pixel-ratio: 1.5),  only screen and (-o-min-device-pixel-ratio: 1.5),  only screen and (min-device-pixel-ratio: 1.5){.icheckbox-pink,.iradio-pink{background-image: url(../images/iCheck/pink@2x.png);\n\t-webkit-background-size: 200px 20px;\n\tbackground-size: 200px 20px}\n}\n/* purple */\n.icheckbox-purple,.iradio-purple{display: block;margin: 0;padding: 0;width: 18px;height: 18px;background: url(../images/iCheck/purple.png) no-repeat;border: none;cursor: pointer}\n.icheckbox-purple,.icheckbox-purple.static:hover{background-position: 0 0}\n.icheckbox-purple.hover,.icheckbox-purple:hover{background-position: -20px 0}\n.icheckbox-purple.checked{background-position: -40px 0}\n.icheckbox-purple.disabled{background-position: -60px 0;cursor: default}\n.icheckbox-purple.checked.disabled{background-position: -80px 0}\n.iradio-purple,.iradio-purple.static:hover{background-position: -100px 0}\n.iradio-purple.hover,.iradio-purple:hover{background-position: -120px 0}\n.iradio-purple.checked{background-position: -140px 0}\n.iradio-purple.disabled{background-position: -160px 0;cursor: default}\n.iradio-purple.checked.disabled{background-position: -180px 0}\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  only screen and (-moz-min-device-pixel-ratio: 1.5),  only screen and (-o-min-device-pixel-ratio: 1.5),  only screen and (min-device-pixel-ratio: 1.5){.icheckbox-purple,.iradio-purple{background-image: url(../images/iCheck/purple@2x.png);\n\t-webkit-background-size: 200px 20px;\n\tbackground-size: 200px 20px}\n}\n\n/*3.4.2.2 Bootsrtap.Switch.css*/\n.has-switch{display:inline-block;cursor:pointer;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;border:1px solid;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);position:relative;text-align:left;overflow:hidden;line-height:8px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;min-width:100px}\n.has-switch.size-MINI{min-width:72px}\n.has-switch.size-S{min-width:80px}\n.has-switch.size-L{min-width:120px}\n.has-switch.deactivate{opacity:.5;filter:alpha(opacity=50);cursor:default!important}\n.has-switch.deactivate label,\n.has-switch.deactivate span{cursor:default!important}\n.has-switch>div{display:inline-block;width:150%;position:relative;top:0}\n.has-switch>div.switch-animate{-webkit-transition:left .5s;-moz-transition:left .5s;-o-transition:left .5s;transition:left .5s}\n.has-switch>div.switch-off{left:-50%}\n.has-switch>div.switch-on{left:0}\n.has-switch input[type=checkbox]{display:none}\n.has-switch span,.has-switch label{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;cursor:pointer;position:relative;display:inline-block;padding-bottom:4px;padding-top:4px;font-size:14px;line-height:20px}\n.has-switch span.size-MINI,.has-switch label.size-MINI{padding-bottom:4px;padding-top:4px;font-size:10px;line-height:9px}\n.has-switch span.size-S,\n.has-switch label.size-S{padding-bottom:3px;padding-top:3px;font-size:12px;line-height:18px}\n.has-switch span.size-L,.has-switch label.size-L{padding-bottom:9px;padding-top:9px;font-size:16px;line-height:normal}\n.has-switch label{text-align:center;margin-top:-1px;margin-bottom:-1px;z-index:100;width:34%;border-left:1px solid #ccc;border-right:1px solid #ccc;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#f5f5f5;\n\tbackground-image:-moz-linear-gradient(top,#fff,#e6e6e6);\n\tbackground-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));\n\tbackground-image:-webkit-linear-gradient(top,#fff,#e6e6e6);\n\tbackground-image:-o-linear-gradient(top,#fff,#e6e6e6);\n\tbackground-image:linear-gradient(to bottom,#fff,#e6e6e6);\n\tbackground-repeat:repeat-x;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);\n\tborder-color:#e6e6e6 #e6e6e6 #bfbfbf;\n\tborder-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);\n\t*background-color:#e6e6e6;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(enabled = false)\n}\n.has-switch label:hover,\n.has-switch label:focus,\n.has-switch label:active,\n.has-switch label.active,\n.has-switch label.disabled,\n.has-switch label[disabled]{color:#fff;background-color:#e6e6e6;*background-color:#d9d9d9}\n.has-switch label:active,\n.has-switch label.active{background-color:#ccc \\9}\n.has-switch label i{color:#000;text-shadow:0 1px 0 #fff;line-height:18px;pointer-events:none}\n.has-switch span{text-align:center;z-index:1;width:33%}\n.has-switch span.switch-left{\n\t-webkit-border-top-left-radius:4px;\n\t-moz-border-radius-topleft:4px;\n\tborder-top-left-radius:4px;\n\t-webkit-border-bottom-left-radius:4px;\n\t-moz-border-radius-bottomleft:4px;\n\tborder-bottom-left-radius:4px\n}\n.has-switch span.switch-right{color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f0f0f0;\n\tbackground-image:-moz-linear-gradient(top,#e6e6e6,#fff);\n\tbackground-image:-webkit-gradient(linear,0 0,0 100%,from(#e6e6e6),to(#fff));\n\tbackground-image:-webkit-linear-gradient(top,#e6e6e6,#fff);\n\tbackground-image:-o-linear-gradient(top,#e6e6e6,#fff);\n\tbackground-image:linear-gradient(to bottom,#e6e6e6,#fff);\n\tbackground-repeat:repeat-x;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6',endColorstr='#ffffffff',GradientType=0);\n\tborder-color:#fff #fff #d9d9d9;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);\n\t*background-color:#fff;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)\n}\n.has-switch span.switch-right:hover,\n.has-switch span.switch-right:focus,\n.has-switch span.switch-right:active,\n.has-switch span.switch-right.active,\n.has-switch span.switch-right.disabled,\n.has-switch span.switch-right[disabled]{color:#333;background-color:#fff;*background-color:#f2f2f2}\n.has-switch span.switch-right:active,\n.has-switch span.switch-right.active{background-color:#e6e6e6 \\9}\n.has-switch span.switch-primary,\n.has-switch span.switch-left{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#005fcc;\n\tbackground-image:-moz-linear-gradient(top,#04c,#08c);\n\tbackground-image:-webkit-gradient(linear,0 0,0 100%,from(#04c),to(#08c));\n\tbackground-image:-webkit-linear-gradient(top,#04c,#08c);\n\tbackground-image:-o-linear-gradient(top,#04c,#08c);\n\tbackground-image:linear-gradient(to bottom,#04c,#08c);\n\tbackground-repeat:repeat-x;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0044cc',endColorstr='#ff0088cc',GradientType=0);\n\tborder-color:#08c #08c #005580;\n\tborder-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);\n\t*background-color:#08c;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(enabled = false)\n}\n.has-switch span.switch-primary:hover,\n.has-switch span.switch-left:hover,\n.has-switch span.switch-primary:focus,\n.has-switch span.switch-left:focus,\n.has-switch span.switch-primary:active,\n.has-switch span.switch-left:active,\n.has-switch span.switch-primary.active,\n.has-switch span.switch-left.active,\n.has-switch span.switch-primary.disabled,\n.has-switch span.switch-left.disabled,\n.has-switch span.switch-primary[disabled],\n.has-switch span.switch-left[disabled]{color:#fff;background-color:#08c;*background-color:#0077b3}\n.has-switch span.switch-primary:active,\n.has-switch span.switch-left:active,\n.has-switch span.switch-primary.active,\n.has-switch span.switch-left.active{background-color:#069 \\9}\n.has-switch span.switch-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#41a7c5;\n\tbackground-image:-moz-linear-gradient(top,#2f96b4,#5bc0de);\n\tbackground-image:-webkit-gradient(linear,0 0,0 100%,from(#2f96b4),to(#5bc0de));\n\tbackground-image:-webkit-linear-gradient(top,#2f96b4,#5bc0de);\n\tbackground-image:-o-linear-gradient(top,#2f96b4,#5bc0de);\n\tbackground-image:linear-gradient(to bottom,#2f96b4,#5bc0de);\n\tbackground-repeat:repeat-x;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2f96b4',endColorstr='#ff5bc0de',GradientType=0);\n\tborder-color:#5bc0de #5bc0de #28a1c5;\n\tborder-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);\n\t*background-color:#5bc0de;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(enabled = false)\n}\n.has-switch span.switch-info:hover,\n.has-switch span.switch-info:focus,\n.has-switch span.switch-info:active,\n.has-switch span.switch-info.active,\n.has-switch span.switch-info.disabled,\n.has-switch span.switch-info[disabled]{color:#fff;background-color:#5bc0de;*background-color:#46b8da}\n.has-switch span.switch-info:active,\n.has-switch span.switch-info.active{background-color:#31b0d5 \\9}\n.has-switch span.switch-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#58b058;\n\tbackground-image:-moz-linear-gradient(top,#51a351,#62c462);\n\tbackground-image:-webkit-gradient(linear,0 0,0 100%,from(#51a351),to(#62c462));\n\tbackground-image:-webkit-linear-gradient(top,#51a351,#62c462);\n\tbackground-image:-o-linear-gradient(top,#51a351,#62c462);\n\tbackground-image:linear-gradient(to bottom,#51a351,#62c462);\n\tbackground-repeat:repeat-x;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff51a351',endColorstr='#ff62c462',GradientType=0);\n\tborder-color:#62c462 #62c462 #3b9e3b;\n\tborder-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);\n\t*background-color:#62c462;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(enabled = false)\n}\n.has-switch span.switch-success:hover,\n.has-switch span.switch-success:focus,\n.has-switch span.switch-success:active,\n.has-switch span.switch-success.active,\n.has-switch span.switch-success.disabled,\n.has-switch span.switch-success[disabled]{color:#fff;background-color:#62c462;*background-color:#4fbd4f}\n.has-switch span.switch-success:active,\n.has-switch span.switch-success.active{background-color:#42b142 \\9}\n.has-switch span.switch-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#f9a123;\n\tbackground-image:-moz-linear-gradient(top,#f89406,#fbb450);\n\tbackground-image:-webkit-gradient(linear,0 0,0 100%,from(#f89406),to(#fbb450));\n\tbackground-image:-webkit-linear-gradient(top,#f89406,#fbb450);\n\tbackground-image:-o-linear-gradient(top,#f89406,#fbb450);\n\tbackground-image:linear-gradient(to bottom,#f89406,#fbb450);\n\tbackground-repeat:repeat-x;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff89406',endColorstr='#fffbb450',GradientType=0);\n\tborder-color:#fbb450 #fbb450 #f89406;\n\tborder-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);\n\t*background-color:#fbb450;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(enabled = false)\n}\n.has-switch span.switch-warning:hover,\n.has-switch span.switch-warning:focus,\n.has-switch span.switch-warning:active,\n.has-switch span.switch-warning.active,\n.has-switch span.switch-warning.disabled,\n.has-switch span.switch-warning[disabled]{color:#fff;background-color:#fbb450;*background-color:#faa937}\n.has-switch span.switch-warning:active,\n.has-switch span.switch-warning.active{background-color:#fa9f1e \\9}\n.has-switch span.switch-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#d14641;\n\tbackground-image:-moz-linear-gradient(top,#bd362f,#ee5f5b);\n\tbackground-image:-webkit-gradient(linear,0 0,0 100%,from(#bd362f),to(#ee5f5b));\n\tbackground-image:-webkit-linear-gradient(top,#bd362f,#ee5f5b);\n\tbackground-image:-o-linear-gradient(top,#bd362f,#ee5f5b);\n\tbackground-image:linear-gradient(to bottom,#bd362f,#ee5f5b);\n\tbackground-repeat:repeat-x;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffbd362f',endColorstr='#ffee5f5b',GradientType=0);\n\tborder-color:#ee5f5b #ee5f5b #e51d18;\n\tborder-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);\n\t*background-color:#ee5f5b;\n\tfilter:progid:DXImageTransform.Microsoft.gradient(enabled = false)\n}\n.has-switch span.switch-danger:hover,\n.has-switch span.switch-danger:focus,\n.has-switch span.switch-danger:active,\n.has-switch span.switch-danger.active,\n.has-switch span.switch-danger.disabled,\n.has-switch span.switch-danger[disabled]{color:#fff;background-color:#ee5f5b;*background-color:#ec4844}\n.has-switch span.switch-danger:active,\n.has-switch span.switch-danger.active{background-color:#e9322d \\9}\n\n/*3.4.3 select 下拉框\n<span class=\"select-box\">\n  <select class=\"select\" size=\"1\" name=\"demo\">\n    <option value=\"1\" selected>默认</option>\n    <option value=\"2\">菜单二</option>\n    <option value=\"3\">菜单三</option>\n  </select>\n</span>\n\tExplain:\n\tselect 是表单元素中最难美化的一个，有两种美化方式：\n\t\t1、修改源生的，修改有限，只能修改个边框，背景，字体。优点：程序方便操作；缺点：丑，浏览器之间存在很大差异。\n\t\t2、将源生的隐藏掉，用其他元素（如div li）通过js模拟下拉交互，然后再传值给源生的select。优点：好看，兼容好；缺点：代码冗余，依赖JS，不方便操作\n*/\n/*方法一、修改源生*/\n.select-box{border:solid 1px #ddd;box-sizing:border-box;vertical-align:middle; width:100%; display:inline-block}\n\t.select{border:solid 1px #ddd;box-sizing:border-box;cursor: pointer;line-height:normal;font-weight: normal;width:100%; white-space:nowrap}\n.select-box .select{ border:none}\n.select-box.inline,\n.select-box.inline .select{ width:auto}\n\n.select-box,\n.select-box.size-M{padding:4px 5px}\n\t.select,.size-M .select{font-size: 14px}\n\n.select-box.size-MINI{padding:0px 5px}\n\t.size-MINI .select{font-size: 12px}\n\n.select-box.size-S{padding:3px 5px}\n\t.size-S .select{font-size: 12px}\n\n.select-box.size-L{padding:8px 5px}\n\t.size-L .select{font-size: 16px}\n\n.select-box.size-XL{padding:10px 5px}\n\t.size-XL .select{font-size: 18px}\n\n@media (max-width: 767px) {\n\t.responsive .select-box{ border:none}\n\t.responsive .select-box .select,\n\t.responsive .select{border:solid 1px #ddd; padding:10px;font-size:16px}\n\t.responsive .select-box,\n\t.responsive .select-box.size-M,\n\t.responsive .select-box.size-MINI,\n\t.responsive .select-box.size-S,\n\t.responsive .select-box.size-L,\n\t.responsive .select-box.size-XL{ height:auto; padding:0}\n}\n\n/*方法二、JS模拟\n<select name=\"demo\" data-enabled=\"false\">\n  <option value=\"1\" selected>默认</option>\n  <option value=\"2\">菜单二</option>\n  <option value=\"3\">菜单三</option>\n</select>\n需要引用2个js文件\n<script type=\"text/javascript\" src=\"lib/squid.js\"></script>\n<script type=\"text/javascript\" src=\"lib/jselect-1.0.js\"></script>\n页面调用方法\n<script type=\"text/javascript\">\nsquid.swing.jselect()\n</script>\n*/\n.select-wrapper {position:relative; display:inline-block;font-size:14px;cursor:default}\n.select-default{zoom: 1;display:block; padding-left:10px; padding-right:30px;background-color:#fff;border:solid 1px #d0d0d0;height:34px;line-height:34px}\n.jsselect.radius{ overflow:visible}\n.jsselect.radius .select-default{ border-radius:4px}\n.jsselect.radius .select-list{border-radius:4px;border-top-left-radius:0;border-top-right-radius:0}\n.select-icon {position: absolute;height:8px;width:12px;right:10px;top:50%; margin-top:-4px;background: url(../images/jselect/iconpic-arrow-down2.png) no-repeat center}\n.unselectable {\n\t-moz-user-select: none;\n\t-khtml-user-select: none;\n\t-webkit-user-select: none;\n\t-o-user-select: none;\n\tuser-select: none}\n\t.select-list {position:absolute;left:0; right:0;top:100%;z-index:1;line-height:34px;max-height:320px; overflow:auto;background-color:#fff;background-clip: padding-box;\n\t_height:expression(this.scrollHeight > 319 ? \"320px\" : \"auto\");\n\t-moz-box-shadow:0 1px 2px rgba(0, 1, 1, 0.2);\n\t-webkit-box-shadow:0 1px 2px rgba(0, 1, 1, 0.2);\n\tbox-shadow:0 1px 2px rgba(0, 1, 1, 0.2);\n\tbox-sizing:border-box;\n\n\tborder:solid 1px #d0d0d0}\n\t\t.select-item {margin: 0;padding: 0}\n\t\t.select-option {background:#fff;line-height:34px;text-align:left;white-space:nowrap; cursor:pointer; border-bottom:1px solid #f2f2f2; padding:0 10px}\n\t\t.select-item .selected {background-color:#148cf1;color:#fff}\n\n/*3.4.4 input-file 文件上传\n\tExample:\n<span class=\"btn-upload\">\n  <a style=\"z-index:2;\" href=\"javascript:void();\" class=\"btn btn-primary radius\"><i class=\"iconfont\">&#xf0020;</i> 浏览文件<input type=\"file\" multiple name=\"file_0\" class=\"input-file\"></a>\n</span>\n\tExplain：把文件选择域设为透明,通过绝对定位覆盖在长的好看的按钮上面。\n*/\n.btn-upload{position: relative; display:inline-block;height:31px; *display:inline;overflow:hidden;vertical-align:middle;cursor:pointer}\n\t.upload-url{cursor: pointer; width:300px}\n\t.input-file{position:absolute; right:0; top:0; cursor: pointer; z-index:1; font-size:30em;opacity:0;filter: alpha(opacity=0)}\n.form-group .upload-btn{ margin-left:-1px}\n.btn-upload .icon-add,.btn-upload .icon-minus{cursor: pointer;display: inline-block;font-family: Arial;font-size: 30px;height: 31px;line-height: 31px;text-align: center;vertical-align: middle;width: 36px}\n@media (max-width: 767px) {\n\t.upload-btn{ display:none}\n\t.upload-url{ display:none}\n}\n\n/*数字表单*/\n.numberControlBox{display:inline-block;overflow:hidden;vertical-align: middle}\n.ncb-up,.ncb-down{font-size:0px;display:block;height:10px;background-color:#f4f4f4;background:-moz-linear-gradient(top,rgb(255,255,255) 0%,rgb(230,230,230) 50%,rgb(255,255,255) 100%);width:24px;border:1px solid #d1d1d1;cursor:pointer}\n.ncb-up{margin-bottom:1px}\n.numberControlBox .ncb_ico{display:block;height:10px;background-image:url(../images/iconpic-arrow.png);background-repeat:no-repeat}\n.ncb-up .ncb_ico{background-position: -22px center}\n.ncb-down .ncb_ico{background-position: 1px center}\n.ncb_btn_hover{border:1px solid #9dc7e7;background-color:#dff2fc;background:-moz-linear-gradient(top,rgb(255,255,255) 0%,rgb(210,237,250) 50%,rgb(255,255,255) 100%)}\n.ncb_btn_selected{border:1px solid #6198c2;background-color:#aee1fb;background:-moz-linear-gradient(top,rgb(255,255,255) 0%,rgb(174,225,251) 50%,rgb(255,255,255) 100%)}\n.input-text[type=\"number\"]{width:80px}\n\n/*3.4.5 spinner 控件*/\n.spinner{display:block;overflow:hidden;width:100px; position:relative; padding-left:29px; padding-right:29px;}\n.spinner .input-text{height:30px; text-align:center; width:100%}\n.spinner a{display:inline-block; position:absolute;top:0; bottom:0; height:28px;line-height:28px;width:28px;cursor:pointer;outline:0; text-decoration:none;text-align:center;font-size:16px;border:1px solid #ddd;background-color:#f7f7f7;}\n.spinner a:hover{ text-decoration:none}\n.spinner a i{ font-style:normal;}\n.spinner a.subtract{ left:0}\n.spinner a.add{ right:0}\n.spinner a.add.disabled,\n.spinner a.subtract.disabled{ color:#999; cursor:not-allowed}\n\n\n/*3.4.6 邮箱提示*/\n.emailSug-wrapper {position: absolute;background: #fff;text-align: left;z-index: 99}\n.emailSug-wrapper .emailSug-list .emailSug-item {font-size: 14px;height: 25px;line-height: 25px;padding-left: 10px;color: #333}\n.emailSug-wrapper .emailSug-list .emailSug-item.active {background: #5a98de;cursor: pointer;color: #fff}\n\n/*3.4.7 表单布局*/\nlabel,.placeholder{font-size:14px}\n.form legend{font-size:20px}/*表单名称*/\n.form .row{margin-top:15px}/*表单行*/\n\t.form-label{display:block; color:#555}/*表单标题*/\n\t.formControls{position:relative}/*表单控制区*/\n\t.formControls > *{vertical-align:middle}\n\t.placeholder{position:absolute; left:4px; top:4px;color:#c6c6c6; cursor:text}/*表单默认值*/\n.form-horizontal .form-label{margin-top:3px;cursor:text;text-align:right}\n.form-horizontal .Validform_checktip{ margin-top:5px}\n/*设置placeholder颜色*/\n::-webkit-input-placeholder {color:#b3b3b3}/* WebKit browsers */\n:-moz-placeholder {color:#b3b3b3}/* Mozilla Firefox 4 to 18 */\n::-moz-placeholder {color:#b3b3b3}/* Mozilla Firefox 19+ */\n:-ms-input-placeholder {color:#b3b3b3}/* Internet Explorer 10+ */\n.placeholder{color:#adb0be; position:absolute; z-index:9}/*不兼容placeholder属性的浏览器，可使用<span class=\"placeholder\">表单默认值</span>*/\n@media (max-width: 767px) {\n\t.form-horizontal .form-label{ text-align:left}\n}\n/*3.4.8 表单验证*/\n/*文本框的错误状态*/\n.Validform_error,input.error,select.error,textarea.error{background-color:#fbe2e2; border-color:#c66161; color:#c00}\n.Validform_wrong,.Validform_right,.Validform_warning{display:inline-block;height:20px;font-size:12px;vertical-align:middle; padding-left:25px}\n/*错误*/\n.Validform_wrong{background:url(../images/validform/iconpic-error.png) no-repeat 0 center;color:#ef392b}\n/*正确*/\n.Validform_right{background:url(../images/validform/iconpic-right.png) no-repeat 0 center}\n/*警告*/\n.Validform_warning{background:url(../images/validform/iconpic-warning.png) no-repeat 0 center;color:#777}\nlabel.error{ position: absolute; right: 18px; top: 5px;color:#ef392b; font-size: 12px}\n.check-box label.error,\n.radio-box label.error{ right:auto; width:150px; left:210px;top:-2px}\n/*密码等级*/\n.passwordStrength b{font-weight:400}\n.passwordStrength b,.passwordStrength span{display:inline-block; vertical-align:middle;line-height:16px;line-height:18px\\9;height:16px}\n.passwordStrength span{width:57px;text-align:center;background-color:#d0d0d0;\tborder-right:1px solid #fff}\n.passwordStrength .last{border-right:none}\n.passwordStrength .bgStrength{color:#fff;background-color:#fcc900}\n/*Validform对话框*/\n#Validform_msg{font-size:14px;width:300px; -webkit-box-shadow:2px 2px 3px #aaa; -moz-box-shadow:2px 2px 3px #aaa; background:#fff; position:absolute; top:0px; right:50px; z-index:99999; display:none;filter: progid:DXImageTransform.Microsoft.Shadow(Strength=3, Direction=135, Color='#999999'); box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.1)}\n#Validform_msg .iframe{position:absolute; left:0px; top:-1px; z-index:-1}\n#Validform_msg .Validform_title{font-size:20px; padding:10px;text-align:left;color:#fff; position:relative; background-color:#fcc900}\n#Validform_msg a.Validform_close:link,#Validform_msg a.Validform_close:visited{position:absolute; right:8px; top:6px; color:#fff; text-decoration:none; font-family:Verdana}\n#Validform_msg a.Validform_close:hover{color:#fff}\n#Validform_msg .Validform_info{padding:10px;border:1px solid #bbb; border-top:none; text-align:left}\n@media (max-width: 767px) {\n\t.responsive .Validform_checktip{margin-top:10px}\n}\n\n/*3.5 按钮\n\tName:\t\t\tstyle_button\n\tExample:\t\t<button class=\"btn radius radius btn-primary|btn-info|btn-success|btn-warning|btn-danger|btn-inverse|btn-link\" type=\"button\">按钮</button>\n\tExplain:\t\tbtn-primary：主要|btn-info：信息|btn-success：成功|btn-warning：警告|btn-danger：危险|btn-inverse：反向|btn-link：链接\n\n*/\n/*关闭*/\n.close{font-size:20px;color: #000;text-shadow: 0 1px 0 #fff;opacity: 0.2;filter: alpha(opacity=20)}\n.close:hover,.close:focus{color: #000;text-decoration: none;cursor: pointer;opacity: 0.4;filter: alpha(opacity=40)}\n\nbutton.close{padding:0;cursor:pointer;background:transparent;border: 0;-webkit-appearance: none}\n/*按钮*/\n.btn{display:inline-block;box-sizing:border-box;cursor:pointer;text-align:center;font-weight:400;white-space:nowrap;vertical-align: middle;-moz-padding-start:npx; -moz-padding-end:npx;border:solid 1px #ddd; background-color:#fff; width:auto;*zoom:1;*overflow:visible;\n\t-webkit-transition:background-color .1s linear;\n\t\t-moz-transition:background-color .1s linear;\n\t\t-o-transition:background-color .1s linear;\n\t\t\ttransition:background-color .1s linear}\na.btn:hover,a.btn:focus,a.btn:active,a.btn.active,a.btn.disabled,a.btn[disabled]{text-decoration:none}\n.btn:active,.btn.active{background-color:#ccc}\n.btn:first-child{*margin-left:0}\n.btn.active,.btn:active{-moz-box-shadow:0 1px 8px rgba(0, 0, 0, 0.125) inset;-webkit-box-shadow:0 1px 8px rgba(0, 0, 0, 0.125) inset; box-shadow:0 1px 8px rgba(0, 0, 0, 0.125) inset}\n\n/*默认——灰色\t通常用于取消*/\n.btn-default{background-color:#e6e6e6;border-color:#e6e6e6}\n.btn-default:hover,\n.btn-default:focus,\n.btn-default:active,\n.btn-default.active{color:#333;background-color:#c7c7c7;border-color:#c7c7c7}\n\n/*主要——主色\t通常用于确定、提交、购买、支付等*/\n.btn-primary{color:#fff;background-color:#5a98de; border-color:#5a98de}\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary:active,\n.btn-primary.active{color:#fff;background-color:#0a6999;border-color:#0a6999}\n\n/*次要按钮*/\n.btn-secondary{color:#fff;background-color:#3bb4f2; border-color:#3bb4f2}\n.btn-secondary:hover,\n.btn-secondary:focus,\n.btn-secondary:active,\n.btn-secondary.active{color:#fff;background-color:#0f9ae0;border-color:#0f9ae0}\n\n/*成功*/\n.btn-success{color:#fff;background-color:#5eb95e; border-color:#5eb95e}\n.btn-success:hover,\n.btn-success:focus,\n.btn-success:active,\n.btn-success.active{color:#fff;background-color:#429842;border-color:#429842}\n\n/*警告*/\n.btn-warning{color:#fff;background-color:#f37b1d; border-color:#f37b1d}\n.btn-warning:hover,\n.btn-warning:focus,\n.btn-warning:active,\n.btn-warning.active{color:#fff;background-color:#c85e0b;border-color:#c85e0b}\n\n/*危险*/\n.btn-danger{color:#fff;background-color:#dd514c; border-color:#dd514c}\n.btn-danger:hover,\n.btn-danger:focus,\n.btn-danger:active,\n.btn-danger.active{color:#fff;background-color:#c62b26;border-color:#c62b26}\n\n/*链接*/\n.btn-link{color:#0e90d2;cursor:pointer;border-color:transparent;background-color:transparent}\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active,\n.btn-link.active{color:#095f8a;text-decoration:underline;background-color:transparent}\n\n/*块级按钮*/\n.btn-block {-moz-box-sizing: border-box;display: block;padding-left: 0;padding-right: 0;width: 100%}\n/* Outline buttons */\n.btn-default-outline{background-color:transparent;border-color:#e6e6e6}\n.btn-default-outline:hover,\n.btn-default-outline:focus,\n.btn-default-outline:active,\n.btn-default-outline.active{color:#333;background-color:transparent;border-color:#c7c7c7}\n\n.btn-primary-outline{color:#5a98de;background-color:transparent; border-color:#5a98de}\n.btn-primary-outline:hover,\n.btn-primary-outline:focus,\n.btn-primary-outline:active,\n.btn-primary-outline.active{color:#0a6999;background-color:transparent;border-color:#0a6999}\n\n.btn-secondary-outline{color:#3bb4f2;background-color:transparent;background-image:none;border-color:#3bb4f2}\n.btn-secondary-outline.active,.btn-secondary-outline.focus,.btn-secondary-outline:active,.btn-secondary-outline:focus,.open>.btn-secondary-outline.dropdown-toggle{color:#fff;background-color:#3bb4f2;border-color:#3bb4f2}\n.btn-secondary-outline:hover{color:#fff;background-color:#3bb4f2;border-color:#3bb4f2}\n.btn-secondary-outline.disabled.focus,.btn-secondary-outline.disabled:focus,.btn-secondary-outline:disabled.focus,.btn-secondary-outline:disabled:focus,fieldset[disabled] .btn-secondary-outline.focus,fieldset[disabled] .btn-secondary-outline:focus{border-color:#0f9ae0}\n\n.btn-success-outline{color:#5eb95e;background-color:transparent;background-image:none;border-color:#5eb95e}\n.btn-success-outline.active,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline:focus,.open>.btn-success-outline.dropdown-toggle{color:#fff;background-color:#5eb95e;border-color:#5eb95e}\n.btn-success-outline:hover{color:#fff;background-color:#5eb95e;border-color:#5eb95e}\n.btn-success-outline.disabled.focus,.btn-success-outline.disabled:focus,.btn-success-outline:disabled.focus,.btn-success-outline:disabled:focus,fieldset[disabled] .btn-success-outline.focus,fieldset[disabled] .btn-success-outline:focus{border-color:#429842}\n\n.btn-warning-outline{color:#f37b1d;background-color:transparent;background-image:none;border-color:#f37b1d}\n.btn-warning-outline.active,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline:focus,.open>.btn-warning-outline.dropdown-toggle{color:#fff;background-color:#f37b1d;border-color:#f37b1d}\n.btn-warning-outline:hover{color:#fff;background-color:#f37b1d;border-color:#f37b1d}\n.btn-warning-outline.disabled.focus,.btn-warning-outline.disabled:focus,.btn-success-outline:disabled.focus,.btn-warning-outline:disabled:focus,fieldset[disabled] .btn-warning-outline.focus,fieldset[disabled] .btn-warning-outline:focus{border-color:#c85e0b}\n\n.btn-danger-outline{color:#dd514c;background-color:transparent;background-image:none;border-color:#dd514c}\n.btn-danger-outline.active,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline:focus,.open>.btn-danger-outline.dropdown-toggle{color:#fff;background-color:#dd514c;border-color:#dd514c}\n.btn-danger-outline:hover{color:#fff;background-color:#dd514c;border-color:#dd514c}\n.btn-danger-outline.disabled.focus,.btn-danger-outline.disabled:focus,.btn-success-outline:disabled.focus,.btn-danger-outline:disabled:focus,fieldset[disabled] .btn-danger-outline.focus,fieldset[disabled] .btn-danger-outline:focus{border-color:#c62b26}\n\n/*禁用状态*/\n.btn.disabled{cursor:not-allowed;background-image:none;opacity:.65;filter:alpha(opacity=65);box-shadow:none; pointer-events:none}\n\n/*表单组*/\n.form-group{ display:inline-block;vertical-align:middle}\n.form-group .input-text{ position:relative; vertical-align:top}\n.form-group.radius{ overflow: hidden}\n.form-group.radius .input-text{border-radius:4px 0 0 4px}\n.form-group.round .input-text{border-radius:1000px 0 0 1000px}\n.form-group .btn{position:relative;margin-left:-1px}\n.form-group.radius .btn{ border-radius:0 4px 4px 0}\n.form-group.round .btn{ border-radius:0 1000px 1000px 0}\n\n/*3.6 图片*/\n/*3.6.1 图片效果\n<img src=\"\" class=\"img-responsive|radius|round|thumbnail\" />\nimg-responsive 响应式    .radius 圆角图片    .round 圆形图片   .thumbnail 缩略图\n*/\n.img-responsive{display:inline-block;max-width:100%;height:auto}\n.thumbnail{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}\n@media (max-width: 767px) {\n\t.img-responsive{width:100%}\n}\n.duang-opacity img{-webkit-transition:opacity .1s linear;-moz-transition:opacity .1s linear;-o-transition:opacity .1s linear;transition:opacity .1s linear}\n.duang-opacity a:hover img,a:hover .opacity img{opacity:0.85;filter: alpha(opacity=85)}\n/*3.6.2 图集效果\n\tName:\t\t\tmodal_album\n\tExample:\n<div class=\"album-item\" style=\"width:160px\">\n\t<div class=\"album-img\">\n\t\t<img src=\"\" style=\"height: 160px;\">\n\t</div>\n\t<div class=\"album-title\">《仙剑奇侠传》赵灵儿<span class=\"c-999\">(20张)</span></div>\n\t<div class=\"album-bg\">\n\t\t<div class=\"album-bg-Fir\"></div>\n\t\t<div class=\"album-bg-Sec\"></div>\n\t</div>\n</div>*/\n.album-item{}\n\t.album-img{ border:1px solid #e0e0e0}\n\t.album-img img{ display:block; width: 100%}\n\t.album-title{display:block;text-align:left;padding:7px 5px;line-height:18px;color:#555;text-decoration:none;font-size:12px;border:solid 1px #e0e0e0;border-top:0}\n\t.album-bg-Fir,.album-bg-Sec{border:1px solid #e6e6e6;border-top:1px solid #f5f5f5;height:1px;margin:0 auto;overflow:hidden}\n\t.album-bg-Fir{ margin:0 3px}\n\t.album-bg-Sec{ margin:0 6px}\n\n/*3.6.3 头像\n\tName:\t\t\tmod_avatar\n\tExample:\t\t<i class=\"avatar avatar-L radius\"><img src=\"static/h-ui/images/ucenter/avatar-default.jpg\"></i>\n*/\n.avatar{display:inline-block;position:relative; overflow:hidden}\n.avatar img{ display:block}\n.avatar.radius,.avatar.radius img{border-radius:50%}\n.avatar,.avatar img{width:32px; height:32px}\n.avatar.size-MINI{ width:16px;height:16px}\n.avatar.size-S,.avatar.size-S img{width:24px; height:24px}\n.avatar.size-M,.avatar.size-M img{width:32px; height:32px}/*默认为中，可以不写，可以理解为：均码*/\n.avatar.size-L,.avatar.size-L img{width:48px; height:48px}\n.avatar.size-XL,.avatar.size-XL img{width:64px; height:64px}\n.avatar.size-XXL,.avatar.size-XXL img{width:100px; height:100px}\n.avatar.size-XXXL,.avatar.size-XXXL img{width:128px; height:128px}\n\n/*3.7 图标\nH-ui采用Font Awesome 3.2.1的整套图标，因为是图标字体，所以可以像控制字体那样随心所欲改变这些图标的颜色、大小、阴影以及任何CSS能控制的属性\n*/\n.iconpic{display:inline-block; vertical-align:sub;*vertical-align:middle;_vertical-align:middle; width:16px; height:16px; background-position:center; background-repeat:no-repeat}\n/*3.8 效果\n\tName:\t\t\tstyle_animation\n\tExample:\t\t<input class=\"btn hui-animation\" val=\"淡入\" type=\"button\" data-tra=\"hui-fadein\" />\n*/\n/* duang 加特效 */\n.hui-bounce,.hui-flip,.hui-flash,.hui-shake,.hui-swing,.hui-wobble,.hui-ring{-webkit-animation:1s ease;-moz-animation:1s ease;-ms-animation:1s ease;animation:1s ease}\n.hui-fadein,.hui-fadeinT,.hui-fadeinR,.hui-fadeinB,.hui-fadeinL,.hui-bouncein,.hui-bounceinT,.hui-bounceinR,.hui-bounceinB,.hui-bounceinL,.hui-rotatein,.hui-rotateinLT,.hui-rotateinLB,.hui-rotateinRT,.hui-rotateinRB,.hui-flipin,.hui-flipinX,.hui-flipinY{-webkit-animation:1s ease-out backwards;-moz-animation:1s ease-out backwards;-ms-animation:1s ease-out backwards;animation:1s ease-out backwards}\n.hui-fadeout,.hui-fadeoutT,.hui-fadeoutR,.hui-fadeoutB,.hui-fadeoutL,.hui-bounceout,.hui-bounceoutT,.hui-bounceoutR,.hui-bounceoutB,.hui-bounceoutL,.hui-rotateout,.hui-rotateoutLT,.hui-rotateoutLB,.hui-rotateoutRT,.hui-rotateoutRB,.hui-flipout,.hui-flipoutX,.hui-flipoutY{-webkit-animation:1s ease-in forwards;-moz-animation:1s ease-in forwards;-ms-animation:1s ease-in forwards;animation:1s ease-in forwards}\n\n/* 淡入 */\n.hui-fadein{-webkit-animation-name:fadein;-moz-animation-name:fadein;-ms-animation-name:fadein;animation-name:fadein}\n/* 淡入-从上 */\n.hui-fadeinT{-webkit-animation-name:fadeinT;-moz-animation-name:fadeinT;-ms-animation-name:fadeinT;animation-name:fadeinT}\n/* 淡入-从右 */\n.hui-fadeinR{-webkit-animation-name:fadeinR;-moz-animation-name:fadeinR;-ms-animation-name:fadeinR;animation-name:fadeinR}\n/* 淡入-从下 */\n.hui-fadeinB{-webkit-animation-name:fadeinB;-moz-animation-name:fadeinB;-ms-animation-name:fadeinB;animation-name:fadeinB}\n/* 淡入-从左 */\n.hui-fadeinL{-webkit-animation-name:fadeinL;-moz-animation-name:fadeinL;-ms-animation-name:fadeinL;animation-name:fadeinL}\n/* 淡出 */\n.hui-fadeout{-webkit-animation-name:fadeout;-moz-animation-name:fadeout;-ms-animation-name:fadeout;animation-name:fadeout}\n\n/* 淡出-向上 */\n.hui-fadeoutT{-webkit-animation-name:fadeoutT;-moz-animation-name:fadeoutT;-ms-animation-name:fadeoutT;animation-name:fadeoutT}\n/* 淡出-向右 */\n.hui-fadeoutR{-webkit-animation-name:fadeoutR;-moz-animation-name:fadeoutR;-ms-animation-name:fadeoutR;animation-name:fadeoutR}\n/* 淡出-向下 */\n.hui-fadeoutB{-webkit-animation-name:fadeoutB;-moz-animation-name:fadeoutB;-ms-animation-name:fadeoutB;animation-name:fadeoutB}\n/* 淡出-向左 */\n.hui-fadeoutL{-webkit-animation-name:fadeoutL;-moz-animation-name:fadeoutL;-ms-animation-name:fadeoutL;animation-name:fadeoutL}\n\n/* 弹跳 */\n.hui-bounce{-webkit-animation-name:bounce;-moz-animation-name:bounce;-ms-animation-name:bounce;animation-name:bounce}\n\n/* 弹入 */\n.hui-bouncein{-webkit-animation-name:bouncein;-moz-animation-name:bouncein;-ms-animation-name:bouncein;animation-name:bouncein}\n/* 弹入-从上 */\n.hui-bounceinT{-webkit-animation-name:bounceinT;-moz-animation-name:bounceinT;-ms-animation-name:bounceinT;animation-name:bounceinT}\n/* 弹入-从右 */\n.hui-bounceinR{-webkit-animation-name:bounceinR;-moz-animation-name:bounceinR;-ms-animation-name:bounceinR;animation-name:bounceinR}\n/* 弹入-从下 */\n.hui-bounceinB{-webkit-animation-name:bounceinB;-moz-animation-name:bounceinB;-ms-animation-name:bounceinB;animation-name:bounceinB}\n/* 弹入-从左 */\n.hui-bounceinL{-webkit-animation-name:bounceinL;-moz-animation-name:bounceinL;-ms-animation-name:bounceinL;animation-name:bounceinL}\n\n/* 弹出 */\n.hui-bounceout{-webkit-animation-name:bounceout;-moz-animation-name:bounceout;-ms-animation-name:bounceout;animation-name:bounceout}\n/* 弹出-向上 */\n.hui-bounceoutT{-webkit-animation-name:bounceoutT;-moz-animation-name:bounceoutT;-ms-animation-name:bounceoutT;animation-name:bounceoutT}\n/* 弹出-向右 */\n.hui-bounceoutR{-webkit-animation-name:bounceoutR;-moz-animation-name:bounceoutR;-ms-animation-name:bounceoutR;animation-name:bounceoutR}\n/* 弹出-向下 */\n.hui-bounceoutB{-webkit-animation-name:bounceoutB;-moz-animation-name:bounceoutB;-ms-animation-name:bounceoutB;animation-name:bounceoutB}\n/* 弹出-向左 */\n.hui-bounceoutL{-webkit-animation-name:bounceoutL;-moz-animation-name:bounceoutL;-ms-animation-name:bounceoutL;animation-name:bounceoutL}\n\n/* 转入 */\n.hui-rotatein{-webkit-animation-name:rotatein;-moz-animation-name:rotatein;-ms-animation-name:rotatein;animation-name:rotatein}\n/* 转入-从左上 */\n.hui-rotateinLT{-webkit-animation-name:rotateinLT;-moz-animation-name:rotateinLT;-ms-animation-name:rotateinLT;animation-name:rotateinLT}\n/* 转入-从左下 */\n.hui-rotateinLB{-webkit-animation-name:rotateinLB;-moz-animation-name:rotateinLB;-ms-animation-name:rotateinLB;animation-name:rotateinLB}\n/* 转入-从右上 */\n.hui-rotateinRT{-webkit-animation-name:rotateinRT;-moz-animation-name:rotateinRT;-ms-animation-name:rotateinRT;animation-name:rotateinRT}\n/* 转入-从右下*/\n.hui-rotateinRB{-webkit-animation-name:rotateinRB;-moz-animation-name:rotateinRB;-ms-animation-name:rotateinRB;animation-name:rotateinRB}\n\n/* 转出 */\n.hui-rotateout{-webkit-animation-name:rotateout;-moz-animation-name:rotateout;-ms-animation-name:rotateout;animation-name:rotateout}\n/* 转出-向左上 */\n.hui-rotateoutLT{-webkit-animation-name:rotateoutLT;-moz-animation-name:rotateoutLT;-ms-animation-name:rotateoutLT;animation-name:rotateoutLT}\n/* 转出-向左下 */\n.hui-rotateoutLB{-webkit-animation-name:rotateoutLB;-moz-animation-name:rotateoutLB;-ms-animation-name:rotateoutLB;animation-name:rotateoutLB}\n/* 转出-向右上 */\n.hui-rotateoutRT{-webkit-animation-name:rotateoutRT;-moz-animation-name:rotateoutRT;-ms-animation-name:rotateoutRT;animation-name:rotateoutRT}\n/* 转出-向右下 */\n.hui-rotateoutRB{-webkit-animation-name:rotateoutRB;-moz-animation-name:rotateoutRB;-ms-animation-name:rotateoutRB;animation-name:rotateoutRB}\n\n/* 翻转 */\n.hui-flip{-webkit-animation-name:flip;-moz-animation-name:flip;-ms-animation-name:flip;animation-name:flip}\n/* 翻入-X轴 */\n.hui-flipinX{-webkit-animation-name:flipinX;-moz-animation-name:flipinX;-ms-animation-name:flipinX;animation-name:flipinX}\n/* 翻入-Y轴 */\n.hui-flipin,.hui-flipinY{-webkit-animation-name:flipinY;-moz-animation-name:flipinY;-ms-animation-name:flipinY;animation-name:flipinY}\n/* 翻出-X轴 */\n.hui-flipoutX{-webkit-animation-name:flipoutX;-moz-animation-name:flipoutX;-ms-animation-name:flipoutX;animation-name:flipoutX}\n/* 翻出-Y轴 */\n.hui-flipout,.hui-flipoutY{-webkit-animation-name:flipoutY;-moz-animation-name:flipoutY;-ms-animation-name:flipoutY;animation-name:flipoutY}\n\n/* 闪烁 */\n.hui-flash{-webkit-animation-name:flash;-moz-animation-name:flash;-ms-animation-name:flash;animation-name:flash}\n/* 震颤 */\n.hui-shake{-webkit-animation-name:shake;-moz-animation-name:shake;-ms-animation-name:shake;animation-name:shake}\n/* 摇摆 */\n.hui-swing{-webkit-animation-name:swing;-moz-animation-name:swing;-ms-animation-name:swing;animation-name:swing}\n/* 摇晃 */\n.hui-wobble{-webkit-animation-name:wobble;-moz-animation-name:wobble;-ms-animation-name:wobble;animation-name:wobble}\n/* 震铃 */\n.hui-ring{-webkit-animation-name:ring;-moz-animation-name:ring;-ms-animation-name:ring;animation-name:ring}\n/* define */\n/* 淡入 */\n@-webkit-keyframes fadein{\n    0%{opacity:0}\n    100%{opacity:1}\n}\n@-moz-keyframes fadein{\n    0%{opacity:0}\n    100%{opacity:1}\n}\n@-ms-keyframes fadein{\n    0%{opacity:0}\n    100%{opacity:1}\n}\n@keyframes fadein{\n    0%{opacity:0}\n    100%{opacity:1}\n}\n/* 淡入-从上 */\n@-webkit-keyframes fadeinT{\n    0%{opacity:0;-webkit-transform:translateY(-100px)}\n    100%{opacity:1;-webkit-transform:translateY(0)}\n}\n@-moz-keyframes fadeinT{\n    0%{opacity:0;-moz-transform:translateY(-100px)}\n    100%{opacity:1;-moz-transform:translateY(0)}\n}\n@-ms-keyframes fadeinT{\n    0%{opacity:0;-ms-transform:translateY(-100px)}\n    100%{opacity:1;-ms-transform:translateY(0)}\n}\n@keyframes fadeinT{\n    0%{opacity:0;transform:translateY(-100px)}\n    100%{opacity:1;transform:translateY(0)}\n}\n/* 淡入-从右 */\n@-webkit-keyframes fadeinR{\n    0%{opacity:0;-webkit-transform:translateX(100px)}\n    100%{opacity:1;-webkit-transform:translateX(0)}\n}\n@-moz-keyframes fadeinR{\n    0%{opacity:0;-moz-transform:translateX(100px)}\n    100%{opacity:1;-moz-transform:translateX(0)}\n}\n@-ms-keyframes fadeinR{\n    0%{opacity:0;-ms-transform:translateX(100px)}\n    100%{opacity:1;-ms-transform:translateX(0)}\n}\n@keyframes fadeinR{\n    0%{opacity:0;transform:translateX(100px)}\n    100%{opacity:1;transform:translateX(0)}\n}\n/* 淡入-从下 */\n@-webkit-keyframes fadeinB{\n    0%{opacity:0;-webkit-transform:translateY(100px)}\n    100%{opacity:1;-webkit-transform:translateY(0)}\n}\n@-moz-keyframes fadeinB{\n    0%{opacity:0;-moz-transform:translateY(100px)}\n    100%{opacity:1;-moz-transform:translateY(0)}\n}\n@-ms-keyframes fadeinB{\n    0%{opacity:0;-ms-transform:translateY(100px)}\n    100%{opacity:1;-ms-transform:translateY(0)}\n}\n@keyframes fadeinB{\n    0%{opacity:0;transform:translateY(100px)}\n    100%{opacity:1;transform:translateY(0)}\n}\n/* 淡入-从左 */\n@-webkit-keyframes fadeinL{\n    0%{opacity:0;-webkit-transform:translateX(-100px)}\n    100%{opacity:1;-webkit-transform:translateX(0)}\n}\n@-moz-keyframes fadeinL{\n    0%{opacity:0;-moz-transform:translateX(-100px)}\n    100%{opacity:1;-moz-transform:translateX(0)}\n}\n@-ms-keyframes fadeinL{\n    0%{opacity:0;-ms-transform:translateX(-100px)}\n    100%{opacity:1;-ms-transform:translateX(0)}\n}\n@keyframes fadeinL{\n    0%{opacity:0;transform:translateX(-100px)}\n    100%{opacity:1;transform:translateX(0)}\n}\n/* 淡出 */\n@-webkit-keyframes fadeout{\n    0%{opacity:1}\n    100%{opacity:0}\n}\n@-moz-keyframes fadeout{\n    0%{opacity:1}\n    100%{opacity:0}\n}\n@-ms-keyframes fadeout{\n    0%{opacity:1}\n    100%{opacity:0}\n}\n@keyframes fadeout{\n    0%{opacity:1}\n    100%{opacity:0}\n}\n/* 淡出-向上 */\n@-webkit-keyframes fadeoutT{\n    0%{opacity:1;-webkit-transform:translateY(0)}\n    100%{opacity:0;-webkit-transform:translateY(-100px)}\n}\n@-moz-keyframes fadeoutT{\n    0%{opacity:1;-moz-transform:translateY(0)}\n    100%{opacity:0;-moz-transform:translateY(-100px)}\n}\n@-ms-keyframes fadeoutT{\n    0%{opacity:1;-ms-transform:translateY(0)}\n    100%{opacity:0;-ms-transform:translateY(-100px)}\n}\n@keyframes fadeoutT{\n    0%{opacity:1;transform:translateY(0)}\n    100%{opacity:0;transform:translateY(-100px)}\n}\n/* 淡出-向右 */\n@-webkit-keyframes fadeoutR{\n    0%{opacity:1;-webkit-transform:translateX(0)}\n    100%{opacity:0;-webkit-transform:translateX(100px)}\n}\n@-moz-keyframes fadeoutR{\n    0%{opacity:1;-moz-transform:translateX(0)}\n    100%{opacity:0;-moz-transform:translateX(100px)}\n}\n@-ms-keyframes fadeoutR{\n    0%{opacity:1;-ms-transform:translateX(0)}\n    100%{opacity:0;-ms-transform:translateX(100px)}\n}\n@keyframes fadeoutR{\n    0%{opacity:1;transform:translateX(0)}\n    100%{opacity:0;transform:translateX(100px)}\n}\n/* 淡出-向下 */\n@-webkit-keyframes fadeoutB{\n    0%{opacity:1;-webkit-transform:translateY(0)}\n    100%{opacity:0;-webkit-transform:translateY(100px)}\n}\n@-moz-keyframes fadeoutB{\n    0%{opacity:1;-moz-transform:translateY(0)}\n    100%{opacity:0;-moz-transform:translateY(100px)}\n}\n@-ms-keyframes fadeoutB{\n    0%{opacity:1;-ms-transform:translateY(0)}\n    100%{opacity:0;-ms-transform:translateY(100px)}\n}\n@keyframes fadeoutB{\n    0%{opacity:1;transform:translateY(0)}\n    100%{opacity:0;transform:translateY(100px)}\n}\n/* 淡出-向左 */\n@-webkit-keyframes fadeoutL{\n    0%{opacity:1;-webkit-transform:translateX(0)}\n    100%{opacity:0;-webkit-transform:translateX(-100px)}\n}\n@-moz-keyframes fadeoutL{\n    0%{opacity:1;-moz-transform:translateX(0)}\n    100%{opacity:0;-moz-transform:translateX(-100px)}\n}\n@-ms-keyframes fadeoutL{\n    0%{opacity:1;-ms-transform:translateX(0)}\n    100%{opacity:0;-ms-transform:translateX(-100px)}\n}\n@keyframes fadeoutL{\n    0%{opacity:1;transform:translateX(0)}\n    100%{opacity:0;transform:translateX(-100px)}\n}\n/* 弹跳 */\n@-webkit-keyframes bounce{\n    0%,20%,50%,80%,100%{-webkit-transform:translateY(0)}\n    40%{-webkit-transform:translateY(-30px)}\n    60%{-webkit-transform:translateY(-15px)}\n}\n@-moz-keyframes bounce{\n    0%,20%,50%,80%,100%{-moz-transform:translateY(0)}\n    40%{-moz-transform:translateY(-30px)}\n    60%{-moz-transform:translateY(-15px)}\n}\n@-ms-keyframes bounce{\n    0%,20%,50%,80%,100%{-ms-transform:translateY(0)}\n    40%{-ms-transform:translateY(-30px)}\n    60%{-ms-transform:translateY(-15px)}\n}\n@keyframes bounce{\n    0%,20%,50%,80%,100%{transform:translateY(0)}\n    40%{transform:translateY(-30px)}\n    60%{transform:translateY(-15px)}\n}\n/* 弹入 */\n@-webkit-keyframes bouncein{\n    0%{opacity:0;-webkit-transform:scale(0.3)}\n    50%{opacity:1;-webkit-transform:scale(1.05)}\n    70%{-webkit-transform:scale(0.9)}\n    100%{-webkit-transform:scale(1)}\n}\n@-moz-keyframes bouncein{\n    0%{opacity:0;-moz-transform:scale(0.3)}\n    50%{opacity:1;-moz-transform:scale(1.05)}\n    70%{-moz-transform:scale(0.9)}\n    100%{-moz-transform:scale(1)}\n}\n@-ms-keyframes bouncein{\n    0%{opacity:0;-ms-transform:scale(0.3)}\n    50%{opacity:1;-ms-transform:scale(1.05)}\n    70%{-ms-transform:scale(0.9)}\n    100%{-ms-transform:scale(1)}\n}\n@keyframes bouncein{\n    0%{opacity:0;transform:scale(0.3)}\n    50%{opacity:1;transform:scale(1.05)}\n    70%{transform:scale(0.9)}\n    100%{transform:scale(1)}\n}\n/* 弹入-从上 */\n@-webkit-keyframes bounceinT{\n    0%{opacity:0;-webkit-transform:translateY(-100px)}\n    60%{opacity:1;-webkit-transform:translateY(30px)}\n    80%{-webkit-transform:translateY(-10px)}\n    100%{-webkit-transform:translateY(0)}\n}\n@-moz-keyframes bounceinT{\n    0%{opacity:0;-moz-transform:translateY(-100px)}\n    60%{opacity:1;-moz-transform:translateY(30px)}\n    80%{-moz-transform:translateY(-10px)}\n    100%{-moz-transform:translateY(0)}\n}\n@-ms-keyframes bounceinT{\n    0%{opacity:0;-ms-transform:translateY(-100px)}\n    60%{opacity:1;-ms-transform:translateY(30px)}\n    80%{-ms-transform:translateY(-10px)}\n    100%{-ms-transform:translateY(0)}\n}\n@keyframes bounceinT{\n    0%{opacity:0;transform:translateY(-100px)}\n    60%{opacity:1;transform:translateY(30px)}\n    80%{transform:translateY(-10px)}\n    100%{transform:translateY(0)}\n}\n/* 弹入-从右 */\n@-webkit-keyframes bounceinR{\n    0%{opacity:0;-webkit-transform:translateX(100px)}\n    60%{opacity:1;-webkit-transform:translateX(-30px)}\n    80%{-webkit-transform:translateX(10px)}\n    100%{-webkit-transform:translateX(0)}\n}\n@-moz-keyframes bounceinR{\n    0%{opacity:0;-moz-transform:translateX(100px)}\n    60%{opacity:1;-moz-transform:translateX(-30px)}\n    80%{-moz-transform:translateX(10px)}\n    100%{-moz-transform:translateX(0)}\n}\n@-ms-keyframes bounceinR{\n    0%{opacity:0;-ms-transform:translateX(100px)}\n    60%{opacity:1;-ms-transform:translateX(-30px)}\n    80%{-ms-transform:translateX(10px)}\n    100%{-ms-transform:translateX(0)}\n}\n@keyframes bounceinR{\n    0%{opacity:0;transform:translateX(100px)}\n    60%{opacity:1;transform:translateX(-30px)}\n    80%{transform:translateX(10px)}\n    100%{transform:translateX(0)}\n}\n/* 弹入-从下 */\n@-webkit-keyframes bounceinB{\n    0%{opacity:0;-webkit-transform:translateY(100px)}\n    60%{opacity:1;-webkit-transform:translateY(-30px)}\n    80%{-webkit-transform:translateY(10px)}\n    100%{-webkit-transform:translateY(0)}\n}\n@-moz-keyframes bounceinB{\n    0%{opacity:0;-moz-transform:translateY(100px)}\n    60%{opacity:1;-moz-transform:translateY(-30px)}\n    80%{-moz-transform:translateY(10px)}\n    100%{-moz-transform:translateY(0)}\n}\n@-ms-keyframes bounceinB{\n    0%{opacity:0;-ms-transform:translateY(100px)}\n    60%{opacity:1;-ms-transform:translateY(-30px)}\n    80%{-ms-transform:translateY(10px)}\n    100%{-ms-transform:translateY(0)}\n}\n@keyframes bounceinB{\n    0%{opacity:0;transform:translateY(100px)}\n    60%{opacity:1;transform:translateY(-30px)}\n    80%{transform:translateY(10px)}\n    100%{transform:translateY(0)}\n}\n/* 弹入-从左 */\n@-webkit-keyframes bounceinL{\n    0%{opacity:0;-webkit-transform:translateX(-100px)}\n    60%{opacity:1;-webkit-transform:translateX(30px)}\n    80%{-webkit-transform:translateX(-10px)}\n    100%{-webkit-transform:translateX(0)}\n}\n@-moz-keyframes bounceinL{\n    0%{opacity:0;-moz-transform:translateX(-100px)}\n    60%{opacity:1;-moz-transform:translateX(30px)}\n    80%{-moz-transform:translateX(-10px)}\n    100%{-moz-transform:translateX(0)}\n}\n@-ms-keyframes bounceinL{\n    0%{opacity:0;-ms-transform:translateX(-100px)}\n    60%{opacity:1;-ms-transform:translateX(30px)}\n    80%{-ms-transform:translateX(-10px)}\n    100%{-ms-transform:translateX(0)}\n}\n@keyframes bounceinL{\n    0%{opacity:0;transform:translateX(-100px)}\n    60%{opacity:1;transform:translateX(30px)}\n    80%{transform:translateX(-10px)}\n    100%{transform:translateX(0)}\n}\n/* 弹出 */\n@-webkit-keyframes bounceout{\n    0%{-webkit-transform:scale(1)}\n    25%{-webkit-transform:scale(0.95)}\n    50%{opacity:1;-webkit-transform:scale(1.1)}\n    100%{opacity:0;-webkit-transform:scale(0.3)}\n}\n@-moz-keyframes bounceout{\n    0%{-moz-transform:scale(1)}\n    25%{-moz-transform:scale(0.95)}\n    50%{opacity:1;-moz-transform:scale(1.1)}\n    100%{opacity:0;-moz-transform:scale(0.3)}\n}\n@-ms-keyframes bounceout{\n    0%{-ms-transform:scale(1)}\n    25%{-ms-transform:scale(0.95)}\n    50%{opacity:1;-ms-transform:scale(1.1)}\n    100%{opacity:0;-ms-transform:scale(0.3)}\n}\n@keyframes bounceout{\n    0%{transform:scale(1)}\n    25%{transform:scale(0.95)}\n    50%{opacity:1;transform:scale(1.1)}\n    100%{opacity:0;transform:scale(0.3)}\n}\n/* 弹出-向上*/\n@-webkit-keyframes bounceoutT{\n    0%{-webkit-transform:translateY(0)}\n    20%{opacity:1;-webkit-transform:translateY(20px)}\n    100%{opacity:0;-webkit-transform:translateY(-100px)}\n}\n@-moz-keyframes bounceoutT{\n    0%{-moz-transform:translateY(0)}\n    20%{opacity:1;-moz-transform:translateY(20px)}\n    100%{opacity:0;-moz-transform:translateY(-100px)}\n}\n@-ms-keyframes bounceoutT{\n    0%{-ms-transform:translateY(0)}\n    20%{opacity:1;-ms-transform:translateY(20px)}\n    100%{opacity:0;-ms-transform:translateY(-100px)}\n}\n@keyframes bounceoutT{\n    0%{transform:translateY(0)}\n    20%{opacity:1;transform:translateY(20px)}\n    100%{opacity:0;transform:translateY(-100px)}\n}\n/* 弹出-向右*/\n@-webkit-keyframes bounceoutR{\n    0%{-webkit-transform:translateX(0)}\n    20%{opacity:1;-webkit-transform:translateX(-20px)}\n    100%{opacity:0;-webkit-transform:translateX(100px)}\n}\n@-moz-keyframes bounceoutR{\n    0%{-moz-transform:translateX(0)}\n    20%{opacity:1;-moz-transform:translateX(-20px)}\n    100%{opacity:0;-moz-transform:translateX(100px)}\n}\n@-ms-keyframes bounceoutR{\n    0%{-ms-transform:translateX(0)}\n    20%{opacity:1;-ms-transform:translateX(-20px)}\n    100%{opacity:0;-ms-transform:translateX(100px)}\n}\n@keyframes bounceoutR{\n    0%{transform:translateX(0)}\n    20%{opacity:1;transform:translateX(-20px)}\n    100%{opacity:0;transform:translateX(100px)}\n}\n/* 弹出-向下 */\n@-webkit-keyframes bounceoutB{\n    0%{-webkit-transform:translateY(0)}\n    20%{opacity:1;-webkit-transform:translateY(-20px)}\n    100%{opacity:0;-webkit-transform:translateY(100px)}\n}\n@-moz-keyframes bounceoutB{\n    0%{-moz-transform:translateY(0)}\n    20%{opacity:1;-moz-transform:translateY(-20px)}\n    100%{opacity:0;-moz-transform:translateY(100px)}\n}\n@-ms-keyframes bounceoutB{\n    0%{-ms-transform:translateY(0)}\n    20%{opacity:1;-ms-transform:translateY(-20px)}\n    100%{opacity:0;-ms-transform:translateY(100px)}\n}\n@keyframes bounceoutB{\n    0%{transform:translateY(0)}\n    20%{opacity:1;transform:translateY(-20px)}\n    100%{opacity:0;transform:translateY(100px)}\n}\n/* 弹出-向左 */\n@-webkit-keyframes bounceoutL{\n    0%{-webkit-transform:translateX(0)}\n    20%{opacity:1;-webkit-transform:translateX(20px)}\n    100%{opacity:0;-webkit-transform:translateX(-100px)}\n}\n@-moz-keyframes bounceoutL{\n    0%{-moz-transform:translateX(0)}\n    20%{opacity:1;-moz-transform:translateX(20px)}\n    100%{opacity:0;-moz-transform:translateX(-100px)}\n}\n@-ms-keyframes bounceoutL{\n    0%{-ms-transform:translateX(0)}\n    20%{opacity:1;-ms-transform:translateX(20px)}\n    100%{opacity:0;-ms-transform:translateX(-100px)}\n}\n@keyframes bounceoutL{\n    0%{transform:translateX(0)}\n    20%{opacity:1;transform:translateX(20px)}\n    100%{opacity:0;transform:translateX(-200px)}\n}\n/* 转入 */\n@-webkit-keyframes rotatein{\n    0%{opacity:0;-webkit-transform:rotate(-200deg)}\n    100%{opacity:1;-webkit-transform:rotate(0)}\n}\n@-moz-keyframes rotatein{\n    0%{opacity:0;-moz-transform:rotate(-200deg)}\n    100%{opacity:1;-moz-transform:rotate(0)}\n}\n@-ms-keyframes rotatein{\n    0%{opacity:0;-ms-transform:rotate(-200deg)}\n    100%{opacity:1;-ms-transform:rotate(0)}\n}\n@keyframes rotatein{\n    0%{opacity:0;transform:rotate(-200deg)}\n    100%{opacity:1;transform:rotate(0)}\n}\n/* 转入-从左上 */\n@-webkit-keyframes rotateinLT{\n    0%{-webkit-transform-origin:left bottom;-webkit-transform:rotate(-90deg);opacity:0}\n    100%{-webkit-transform-origin:left bottom;-webkit-transform:rotate(0);opacity:1}\n}\n@-moz-keyframes rotateinLT{\n    0%{-moz-transform-origin:left bottom;-moz-transform:rotate(-90deg);opacity:0}\n    100%{-moz-transform-origin:left bottom;-moz-transform:rotate(0);opacity:1}\n}\n@-ms-keyframes rotateinLT{\n    0%{-ms-transform-origin:left bottom;-ms-transform:rotate(-90deg);opacity:0}\n    100%{-ms-transform-origin:left bottom;-ms-transform:rotate(0);opacity:1}\n}\n@keyframes rotateinLT{\n    0%{transform-origin:left bottom;transform:rotate(-90deg);opacity:0}\n    100%{transform-origin:left bottom;transform:rotate(0);opacity:1}\n}\n/* 转入-从左下 */\n@-webkit-keyframes rotateineftB{\n    0%{-webkit-transform-origin:left bottom;-webkit-transform:rotate(90deg);opacity:0}\n    100%{-webkit-transform-origin:left bottom;-webkit-transform:rotate(0);opacity:1}\n}\n@-moz-keyframes rotateineftB{\n    0%{-moz-transform-origin:left bottom;-moz-transform:rotate(90deg);opacity:0}\n    100%{-moz-transform-origin:left bottom;-moz-transform:rotate(0);opacity:1}\n}\n@-ms-keyframes rotateineftB{\n    0%{-ms-transform-origin:left bottom;-ms-transform:rotate(90deg);opacity:0}\n    100%{-ms-transform-origin:left bottom;-ms-transform:rotate(0);opacity:1}\n}\n@keyframes rotateineftB{\n    0%{transform-origin:left bottom;transform:rotate(90deg);opacity:0}\n    100%{transform-origin:left bottom;transform:rotate(0);opacity:1}\n}\n/* 转入-从右上 */\n@-webkit-keyframes rotateinRT{\n    0%{-webkit-transform-origin:right bottom;-webkit-transform:rotate(90deg);opacity:0}\n    100%{-webkit-transform-origin:right bottom;-webkit-transform:rotate(0);opacity:1}\n}\n@-moz-keyframes rotateinRT{\n    0%{-moz-transform-origin:right bottom;-moz-transform:rotate(90deg);opacity:0}\n    100%{-moz-transform-origin:right bottom;-moz-transform:rotate(0);opacity:1}\n}\n@-ms-keyframes rotateinRT{\n    0%{-ms-transform-origin:right bottom;-ms-transform:rotate(90deg);opacity:0}\n    100%{-ms-transform-origin:right bottom;-ms-transform:rotate(0);opacity:1}\n}\n@keyframes rotateinRT{\n    0%{transform-origin:right bottom;transform:rotate(90deg);opacity:0}\n    100%{transform-origin:right bottom;transform:rotate(0);opacity:1}\n}\n/* 转入-从右下*/\n@-webkit-keyframes rotateinRB{\n    0%{-webkit-transform-origin:right bottom;-webkit-transform:rotate(-90deg);opacity:0}\n    100%{-webkit-transform-origin:right bottom;-webkit-transform:rotate(0);opacity:1}\n}\n@-moz-keyframes rotateinRB{\n    0%{-moz-transform-origin:right bottom;-moz-transform:rotate(-90deg);opacity:0}\n    100%{-moz-transform-origin:right bottom;-moz-transform:rotate(0);opacity:1}\n}\n@-ms-keyframes rotateinRB{\n    0%{-ms-transform-origin:right bottom;-ms-transform:rotate(-90deg);opacity:0}\n    100%{-ms-transform-origin:right bottom;-ms-transform:rotate(0);opacity:1}\n}\n@keyframes rotateinRB{\n    0%{transform-origin:right bottom;transform:rotate(-90deg);opacity:0}\n    100%{transform-origin:right bottom;transform:rotate(0);opacity:1}\n}\n/* 转出 */\n@-webkit-keyframes rotateout{\n    0%{-webkit-transform-origin:center center;-webkit-transform:rotate(0);opacity:1}\n    100%{-webkit-transform-origin:center center;-webkit-transform:rotate(200deg);opacity:0}\n}\n@-moz-keyframes rotateout{\n    0%{-moz-transform-origin:center center;-moz-transform:rotate(0);opacity:1}\n    100%{-moz-transform-origin:center center;-moz-transform:rotate(200deg);opacity:0}\n}\n@-ms-keyframes rotateout{\n    0%{-ms-transform-origin:center center;-ms-transform:rotate(0);opacity:1}\n    100%{-ms-transform-origin:center center;-ms-transform:rotate(200deg);opacity:0}\n}\n@keyframes rotateout{\n    0%{transform-origin:center center;transform:rotate(0);opacity:1}\n    100%{transform-origin:center center;transform:rotate(200deg);opacity:0}\n}\n/* 转出-向左上 */\n@-webkit-keyframes rotateoutLT{\n    0%{-webkit-transform-origin:left bottom;-webkit-transform:rotate(0);opacity:1}\n    100%{-webkit-transform-origin:left bottom;-webkit-transform:rotate(-90deg);opacity:0}\n}\n@-moz-keyframes rotateoutLT{\n    0%{-moz-transform-origin:left bottom;-moz-transform:rotate(0);opacity:1}\n    100%{-moz-transform-origin:left bottom;-moz-transform:rotate(-90deg);opacity:0}\n}\n@-ms-keyframes rotateoutLT{\n    0%{-ms-transform-origin:left bottom;-ms-transform:rotate(0);opacity:1}\n    100%{-ms-transform-origin:left bottom;-ms-transform:rotate(-90deg);opacity:0}\n}\n@keyframes rotateoutLT{\n    0%{transform-origin:left bottom;transform:rotate(0);opacity:1}\n    100%{transform-origin:left bottom;transform:rotate(-90deg);opacity:0}\n}\n/* 转出-向左下 */\n@-webkit-keyframes rotateoutLB{\n    0%{-webkit-transform-origin:left bottom;-webkit-transform:rotate(0);opacity:1}\n    100%{-webkit-transform-origin:left bottom;-webkit-transform:rotate(90deg);opacity:0}\n}\n@-moz-keyframes rotateoutLB{\n    0%{-moz-transform-origin:left bottom;-moz-transform:rotate(0);opacity:1}\n    100%{-moz-transform-origin:left bottom;-moz-transform:rotate(90deg);opacity:0}\n}\n@-ms-keyframes rotateoutLB{\n    0%{-ms-transform-origin:left bottom;-ms-transform:rotate(0);opacity:1}\n    100%{-ms-transform-origin:left bottom;-ms-transform:rotate(90deg);opacity:0}\n}\n@keyframes rotateoutLB{\n    0%{transform-origin:left bottom;transform:rotate(0);opacity:1}\n    100%{transform-origin:left bottom;transform:rotate(90deg);opacity:0}\n}\n/* 转出-向右上 */\n@-webkit-keyframes rotateoutRT{\n    0%{-webkit-transform-origin:right bottom;-webkit-transform:rotate(0);opacity:1}\n    100%{-webkit-transform-origin:right bottom;-webkit-transform:rotate(90deg);opacity:0}\n}\n@-moz-keyframes rotateoutRT{\n    0%{-moz-transform-origin:right bottom;-moz-transform:rotate(0);opacity:1}\n    100%{-moz-transform-origin:right bottom;-moz-transform:rotate(90deg);opacity:0}\n}\n@-ms-keyframes rotateoutRT{\n    0%{-ms-transform-origin:right bottom;-ms-transform:rotate(0);opacity:1}\n    100%{-ms-transform-origin:right bottom;-ms-transform:rotate(90deg);opacity:0}\n}\n@keyframes rotateoutRT{\n    0%{transform-origin:right bottom;transform:rotate(0);opacity:1}\n    100%{transform-origin:right bottom;transform:rotate(90deg);opacity:0}\n}\n/* 转出-向右下 */\n@-webkit-keyframes rotateoutBR{\n    0%{-webkit-transform-origin:right bottom;-webkit-transform:rotate(0);opacity:1}\n    100%{-webkit-transform-origin:right bottom;-webkit-transform:rotate(-90deg);opacity:0}\n}\n@-moz-keyframes rotateoutBR{\n    0%{-moz-transform-origin:right bottom;-moz-transform:rotate(0);opacity:1}\n    100%{-moz-transform-origin:right bottom;-moz-transform:rotate(-90deg);opacity:0}\n}\n@-ms-keyframes rotateoutBR{\n    0%{-ms-transform-origin:right bottom;-ms-transform:rotate(0);opacity:1}\n    100%{-ms-transform-origin:right bottom;-ms-transform:rotate(-90deg);opacity:0}\n}\n@keyframes rotateoutBR{\n    0%{transform-origin:right bottom;transform:rotate(0);opacity:1}\n    100%{transform-origin:right bottom;transform:rotate(-90deg);opacity:0}\n}\n/* 翻转 */\n@-webkit-keyframes flip{\n    0%{-webkit-transform:perspective(400px) rotateY(0);-webkit-animation-timing-function:ease-out}\n    40%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(170deg);-webkit-animation-timing-function:ease-out}\n    50%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(190deg) scale(1);-webkit-animation-timing-function:ease-in}\n    80%{-webkit-transform:perspective(400px) rotateY(360deg) scale(0.95);-webkit-animation-timing-function:ease-in}\n    100%{-webkit-transform:perspective(400px) scale(1);-webkit-animation-timing-function:ease-in}\n}\n@-moz-keyframes flip{\n    0%{-moz-transform:perspective(400px) rotateY(0);-moz-animation-timing-function:ease-out}\n    40%{-moz-transform:perspective(400px) translateZ(150px) rotateY(170deg);-moz-animation-timing-function:ease-out}\n    50%{-moz-transform:perspective(400px) translateZ(150px) rotateY(190deg) scale(1);-moz-animation-timing-function:ease-in}\n    80%{-moz-transform:perspective(400px) rotateY(360deg) scale(0.95);-moz-animation-timing-function:ease-in}\n    100%{-moz-transform:perspective(400px) scale(1);-moz-animation-timing-function:ease-in}\n}\n@-ms-keyframes flip{\n    0%{-ms-transform:perspective(400px) rotateY(0);-ms-animation-timing-function:ease-out}\n    40%{-ms-transform:perspective(400px) translateZ(150px) rotateY(170deg);-ms-animation-timing-function:ease-out}\n    50%{-ms-transform:perspective(400px) translateZ(150px) rotateY(190deg) scale(1);-ms-animation-timing-function:ease-in}\n    80%{-ms-transform:perspective(400px) rotateY(360deg) scale(0.95);-ms-animation-timing-function:ease-in}\n    100%{-ms-transform:perspective(400px) scale(1);-ms-animation-timing-function:ease-in}\n}\n@keyframes flip{\n    0%{transform:perspective(400px) rotateY(0);animation-timing-function:ease-out}\n    40%{transform:perspective(400px) translateZ(150px) rotateY(170deg);animation-timing-function:ease-out}\n    50%{transform:perspective(400px) translateZ(150px) rotateY(190deg) scale(1);animation-timing-function:ease-in}\n    80%{transform:perspective(400px) rotateY(360deg) scale(0.95);animation-timing-function:ease-in}\n    100%{transform:perspective(400px) scale(1);animation-timing-function:ease-in}\n}\n/* 翻入-X轴 */\n@-webkit-keyframes flipinX{\n    0%{-webkit-transform:perspective(400px) rotateX(90deg);opacity:0}\n    40%{-webkit-transform:perspective(400px) rotateX(-10deg)}\n    70%{-webkit-transform:perspective(400px) rotateX(10deg)}\n    100%{-webkit-transform:perspective(400px) rotateX(0);opacity:1}\n}\n@-moz-keyframes flipinX{\n    0%{-moz-transform:perspective(400px) rotateX(90deg);opacity:0}\n    40%{-moz-transform:perspective(400px) rotateX(-10deg)}\n    70%{-moz-transform:perspective(400px) rotateX(10deg)}\n    100%{-moz-transform:perspective(400px) rotateX(0);opacity:1}\n}\n@-ms-keyframes flipinX{\n    0%{-ms-transform:perspective(400px) rotateX(90deg);opacity:0}\n    40%{-ms-transform:perspective(400px) rotateX(-10deg)}\n    70%{-ms-transform:perspective(400px) rotateX(10deg)}\n    100%{-ms-transform:perspective(400px) rotateX(0);opacity:1}\n}\n@keyframes flipinX{\n    0%{transform:perspective(400px) rotateX(90deg);opacity:0}\n    40%{transform:perspective(400px) rotateX(-10deg)}\n    70%{transform:perspective(400px) rotateX(10deg)}\n    100%{transform:perspective(400px) rotateX(0);opacity:1}\n}\n/* 翻入-Y轴 */\n@-webkit-keyframes flipinY{\n    0%{-webkit-transform:perspective(400px) rotateY(90deg);opacity:0}\n    40%{-webkit-transform:perspective(400px) rotateY(-10deg)}\n    70%{-webkit-transform:perspective(400px) rotateY(10deg)}\n    100%{-webkit-transform:perspective(400px) rotateY(0);opacity:1}\n}\n@-moz-keyframes flipinY{\n    0%{-moz-transform:perspective(400px) rotateY(90deg);opacity:0}\n    40%{-moz-transform:perspective(400px) rotateY(-10deg)}\n    70%{-moz-transform:perspective(400px) rotateY(10deg)}\n    100%{-moz-transform:perspective(400px) rotateY(0);opacity:1}\n}\n@-ms-keyframes flipinY{\n    0%{-ms-transform:perspective(400px) rotateY(90deg);opacity:0}\n    40%{-ms-transform:perspective(400px) rotateY(-10deg)}\n    70%{-ms-transform:perspective(400px) rotateY(10deg)}\n    100%{-ms-transform:perspective(400px) rotateY(0);opacity:1}\n}\n@keyframes flipinY{\n    0%{transform:perspective(400px) rotateY(90deg);opacity:0}\n    40%{transform:perspective(400px) rotateY(-10deg)}\n    70%{transform:perspective(400px) rotateY(10deg)}\n    100%{transform:perspective(400px) rotateY(0);opacity:1}\n}\n/* 翻出-X轴 */\n@-webkit-keyframes flipoutX{\n    0%{-webkit-transform:perspective(400px) rotateX(0);opacity:1}\n    100%{-webkit-transform:perspective(400px) rotateX(90deg);opacity:0}\n}\n@-moz-keyframes flipoutX{\n    0%{-moz-transform:perspective(400px) rotateX(0);opacity:1}\n    100%{-moz-transform:perspective(400px) rotateX(90deg);opacity:0}\n}\n@-ms-keyframes flipoutX{\n    0%{-ms-transform:perspective(400px) rotateX(0);opacity:1}\n    100%{-ms-transform:perspective(400px) rotateX(90deg);opacity:0}\n}\n@keyframes flipoutX{\n    0%{transform:perspective(400px) rotateX(0);opacity:1}\n    100%{transform:perspective(400px) rotateX(90deg);opacity:0}\n}\n/* 翻出-Y轴 */\n@-webkit-keyframes flipoutY{\n    0%{-webkit-transform:perspective(400px) rotateY(0);opacity:1}\n    100%{-webkit-transform:perspective(400px) rotateY(90deg);opacity:0}\n}\n@-moz-keyframes flipoutY{\n    0%{-moz-transform:perspective(400px) rotateY(0);opacity:1}\n    100%{-moz-transform:perspective(400px) rotateY(90deg);opacity:0}\n}\n@-ms-keyframes flipoutY{\n    0%{-ms-transform:perspective(400px) rotateY(0);opacity:1}\n    100%{-ms-transform:perspective(400px) rotateY(90deg);opacity:0}\n}\n@keyframes flipoutY{\n    0%{transform:perspective(400px) rotateY(0);opacity:1}\n    100%{transform:perspective(400px) rotateY(90deg);opacity:0}\n}\n/* 闪烁 */\n@-webkit-keyframes flash{\n    0%,50%,100%{opacity:1}\n    25%,75%{opacity:0}\n}\n@-moz-keyframes flash{\n    0%,50%,100%{opacity:1}\n    25%,75%{opacity:0}\n}\n@-ms-keyframes flash{\n    0%,50%,100%{opacity:1}\n    25%,75%{opacity:0}\n}\n@keyframes flash{\n    0%,50%,100%{opacity:1}\n    25%,75%{opacity:0}\n}\n/* 震颤 */\n@-webkit-keyframes shake{\n    0%,100%{-webkit-transform:translateX(0)}\n    10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px)}\n    20%,40%,60%,80%{-webkit-transform:translateX(10px)}\n}\n@-moz-keyframes shake{\n    0%,100%{-moz-transform:translateX(0)}\n    10%,30%,50%,70%,90%{-moz-transform:translateX(-10px)}\n    20%,40%,60%,80%{-moz-transform:translateX(10px)}\n}\n@-ms-keyframes shake{\n    0%,100%{-ms-transform:translateX(0)}\n    10%,30%,50%,70%,90%{-ms-transform:translateX(-10px)}\n    20%,40%,60%,80%{-ms-transform:translateX(10px)}\n}\n@keyframes shake{\n    0%,100%{transform:translateX(0)}\n    10%,30%,50%,70%,90%{transform:translateX(-10px)}\n    20%,40%,60%,80%{transform:translateX(10px)}\n}\n/* 摇摆 */\n@-webkit-keyframes swing{\n    20%{-webkit-transform:rotate(15deg)}\n    40%{-webkit-transform:rotate(-10deg)}\n    60%{-webkit-transform:rotate(5deg)}\n    80%{-webkit-transform:rotate(-5deg)}\n    100%{-webkit-transform:rotate(0)}\n}\n@-moz-keyframes swing{\n    20%{-moz-transform:rotate(15deg)}\n    40%{-moz-transform:rotate(-10deg)}\n    60%{-moz-transform:rotate(5deg)}\n    80%{-moz-transform:rotate(-5deg)}\n    100%{-moz-transform:rotate(0)}\n}\n@-ms-keyframes swing{\n    20%{-ms-transform:rotate(15deg)}\n    40%{-ms-transform:rotate(-10deg)}\n    60%{-ms-transform:rotate(5deg)}\n    80%{-ms-transform:rotate(-5deg)}\n    100%{-ms-transform:rotate(0)}\n}\n@keyframes swing{\n    20%{transform:rotate(15deg)}\n    40%{transform:rotate(-10deg)}\n    60%{transform:rotate(5deg)}\n    80%{transform:rotate(-5deg)}\n    100%{transform:rotate(0)}\n}\n/* 摇晃 */\n@-webkit-keyframes wobble{\n    0%{-webkit-transform:translateX(0)}\n    15%{-webkit-transform:translateX(-100px) rotate(-5deg)}\n    30%{-webkit-transform:translateX(80px) rotate(3deg)}\n    45%{-webkit-transform:translateX(-65px) rotate(-3deg)}\n    60%{-webkit-transform:translateX(40px) rotate(2deg)}\n    75%{-webkit-transform:translateX(-20px) rotate(-1deg)}\n    100%{-webkit-transform:translateX(0)}\n}\n@-moz-keyframes wobble{\n    0%{-moz-transform:translateX(0)}\n    15%{-moz-transform:translateX(-100px) rotate(-5deg)}\n    30%{-moz-transform:translateX(80px) rotate(3deg)}\n    45%{-moz-transform:translateX(-65px) rotate(-3deg)}\n    60%{-moz-transform:translateX(40px) rotate(2deg)}\n    75%{-moz-transform:translateX(-20px) rotate(-1deg)}\n    100%{-moz-transform:translateX(0)}\n}\n@-ms-keyframes wobble{\n    0%{-ms-transform:translateX(0)}\n    15%{-ms-transform:translateX(-100px) rotate(-5deg)}\n    30%{-ms-transform:translateX(80px) rotate(3deg)}\n    45%{-ms-transform:translateX(-65px) rotate(-3deg)}\n    60%{-ms-transform:translateX(40px) rotate(2deg)}\n    75%{-ms-transform:translateX(-20px) rotate(-1deg)}\n    100%{-ms-transform:translateX(0)}\n}\n@keyframes wobble{\n    0%{transform:translateX(0)}\n    15%{transform:translateX(-100px) rotate(-5deg)}\n    30%{transform:translateX(80px) rotate(3deg)}\n    45%{transform:translateX(-65px) rotate(-3deg)}\n    60%{transform:translateX(40px) rotate(2deg)}\n    75%{transform:translateX(-20px) rotate(-1deg)}\n    100%{transform:translateX(0)}\n}\n/* 震铃 */\n@-webkit-keyframes ring{\n    0%{-webkit-transform:scale(1)}\n    10%,20%{-webkit-transform:scale(0.9) rotate(-3deg)}\n    30%,50%,70%,90%{-webkit-transform:scale(1.1) rotate(3deg)}\n    40%,60%,80%{-webkit-transform:scale(1.1) rotate(-3deg)}\n    100%{-webkit-transform:scale(1) rotate(0)}\n}\n@-moz-keyframes ring{\n    0%{-moz-transform:scale(1)}\n    10%,20%{-moz-transform:scale(0.9) rotate(-3deg)}\n    30%,50%,70%,90%{-moz-transform:scale(1.1) rotate(3deg)}\n    40%,60%,80%{-moz-transform:scale(1.1) rotate(-3deg)}\n    100%{-moz-transform:scale(1) rotate(0)}\n}\n@-ms-keyframes ring{\n    0%{-ms-transform:scale(1)}\n    10%,20%{-ms-transform:scale(0.9) rotate(-3deg)}\n    30%,50%,70%,90%{-ms-transform:scale(1.1) rotate(3deg)}\n    40%,60%,80%{-ms-transform:scale(1.1) rotate(-3deg)}\n    100%{-ms-transform:scale(1) rotate(0)}\n}\n@keyframes ring{\n    0%{transform:scale(1)}\n    10%,20%{transform:scale(0.9) rotate(-3deg)}\n    30%,50%,70%,90%{transform:scale(1.1) rotate(3deg)}\n    40%,60%,80%{transform:scale(1.1) rotate(-3deg)}\n    100%{transform:scale(1) rotate(0)}\n}\n/*4.1 按钮组\n  Name:     mod_btn-group\n  Example:\n<div class=\"btn-group\">\n  <span class=\"btn btn-primary radius\">左边按钮</span>\n  <span class=\"btn btn-default radius\">中间按钮</span>\n  <span class=\"btn btn-default radius\">中间按钮</span>\n  <span class=\"btn btn-default radius\">右边按钮</span>\n</div>\n  Explain:\n*/\n.btn-group{ font-size:0}\n.btn-group .btn{ margin-left:-1px}\n.btn-group .btn:not(:first-child):not(:last-child):not(.dropdown-toggle){ border-radius:0}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius: 0;border-top-right-radius: 0}\n.btn-group > .btn:last-child:not(:first-child),.btn-group > .dropdown-toggle:not(:first-child) {border-bottom-left-radius: 0;border-top-left-radius: 0}\n\n/*4.2.1 导航条\n\tName:\t\t\tmod_nav\n\tExample:\n<header class=\"navbar-wrapper\">\n\t<nav class=\"nav navbar-nav nav-collapse\" role=\"navigation\" id=\"Hui-navbar\">\n\t\t<ul class=\"cl\">\n\t\t\t<li class=\"current\"><a href=\"/\">首页</a></li>\n\t\t\t<li><a href=\"#\">核心</a></li>\n\t\t\t<li><a href=\"#\">扩展</a></li>\n\t\t\t<li class=\"dropDown dropDown_hover\"><a href=\"#\" class=\"dropDown_A\">一级导航 <i class=\"Hui-iconfont\">&#xe6d5;</i></a>\n\t\t\t\t<ul class=\"dropDown-menu menu radius box-shadow\">\n\t\t\t\t\t<li><a href=\"#\">二级导航</a></li>\n\t\t\t\t\t<li><a href=\"#\">二级导航<i class=\"arrow Hui-iconfont\">&#xe6d7;</i></a>\n\t\t\t\t\t\t<ul class=\"menu\">\n\t\t\t\t\t\t\t<li><a href=\"javascript:;\">三级菜单<i class=\"arrow Hui-iconfont\">&#xe6d7;</i></a>\n\t\t\t\t\t\t\t\t<ul class=\"menu\">\n\t\t\t\t\t\t\t\t\t<li><a href=\"javascript:;\">四级菜单</a></li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"javascript:;\">四级菜单</a></li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"javascript:;\">四级菜单</a></li>\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li><a href=\"#\">三级导航</a></li>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li><a href=\"#\">二级导航</a></li>\n\t\t\t\t\t<li class=\"disabled\"><a href=\"javascript:;\">二级菜单</a></li>\n\t\t\t\t</ul>\n\t\t\t</li>\n\t\t\t<li><a href=\"#\">联系我们</a></li>\n\t\t</ul>\n\t</nav>\n</header>\n\tExplain: 鼠标经过状态a:hover，当前选中状态li:current。\n*/\n/*导航条*/\n.navbar-wrapper{ height: 45px}\n.navbar{ position:relative; z-index:1030; background-color: #fff}\n.navbar-black{ background-color: #222}\n.navbar-fixed-top{ position:fixed; top:0;left: 0; right: 0; z-index:1030}\n\n  /*logo*/\n\t.logo{ display:inline-block; text-decoration:none; cursor:pointer; background-repeat: no-repeat; background-position: left center; background-size: auto 100%}\n\ta.logo:hover{ text-decoration:none}\n\t.navbar .logo{height: 44px;line-height: 44px;margin-right: 10px;float: left}\n\t.navbar-logo,.navbar-logo-m{font-size: 16px}\n\t.navbar-slogan{ font-size:12px; cursor: default}\n\t.navbar .container{ position:relative}\n\t.navbar .container .navbar-userbar{ right:0px}\n  /*导航*/\n  .nav{ z-index:1}\n  .nav > ul{ font-size:0; line-height:0}\n  .nav > ul > li{ position:relative; float:left}\n  .nav > ul > li,.nav > ul > li > a{ display:inline-block;text-align:center}\n  .nav > ul > li > a{ padding:0 20px}\n  .nav > ul > li > a:hover,.nav > ul > li.current > a{background-color:rgba(255,255,255,0.2); text-decoration:none;\n\t\t-webkit-transition: background-color 0.3s ease 0s;\n\t\t-moz-transition: background-color 0.3s ease 0s;\n\t\t-o-transition: background-color 0.3s ease 0s;\n\t\t-ms-transition: background-color 0.3s ease 0s;\n\t\ttransition: background-color 0.3s ease 0s\n  }\n  .navbar-nav > ul > li,.navbar-nav > ul > li > a{line-height:44px;font-size:14px}\n  @media (max-width: 767px) {\n    .navbar-wrapper{ height: 45px!important}\n    .logo{ margin-right: 0}\n    .navbar .logo{height: 44px!important;line-height: 44px!important}\n    .navbar-nav{display: none; float: none!important}\n    .navbar-nav > ul > li{ width: 100%; text-align: left; border-bottom: solid 1px #eee}\n    .navbar-nav > ul > li > a{display:block;padding:0 15px; text-align: left}\n    .navbar-nav > ul > li.dropDown.open > .dropDown-menu{ display: none}\n    .navbar-nav > ul > li.dropDown > .dropDown_A > .Hui-iconfont{ display: none}\n    .navbar-nav > ul > li,\n\t.navbar-nav > ul > li > a{height: 44px!important;line-height: 44px!important}\n\n    .nav-collapse > ul,.nav-collapse > ul >li {width: 100%;display: block}\n    .js .nav-collapse {position: absolute;display: block;float:none; clear:both;max-height: 0;clip: rect(0 0 0 0);margin-left: -15px; margin-right: -15px;overflow: hidden;\n      -webkt-transition:max-height 284ms ease 0s;\n      -moz-transition:max-height 284ms ease 0s;\n      -o-transition:max-height 284ms ease 0s;\n      -ms-transition:max-height 284ms ease 0s;\n      transition:max-height 284ms ease 0s}\n    .js-nav-active .nav-collapse.closed {max-height: none}\n    .nav-collapse.opened {max-height: 9999px}\n\n  }\n\n/*导航条风格-黑色*/\n.navbar-black{background-color:#222;border-bottom:#080808 1px solid;-moz-box-shadow: 0 0 4px #333333;-webkit-box-shadow: 0 0 4px #333333;box-shadow: 0 0 4px #333333}\n.navbar-black .logo{ color: #fff }\n.navbar-black .navbar-logo-m{color: #eee}\n.navbar-black .navbar-nav > ul > li,\n.navbar-black .navbar-nav > ul > li > a{ color:#fff}\n.navbar-black .navbar-nav > ul > li > a:hover,\n.navbar-black .navbar-nav > ul > li.current > a{color:#fff}\n.navbar-black .navbar-userbar{ color: #fff}\n@media (max-width: 767px) {\n  .navbar-black .navbar-nav > ul > li{border-bottom: solid 1px #222}\n  .navbar-black .navbar-nav > ul > li > a:hover,\n  .navbar-black .navbar-nav > ul > li.current > a{ background: #777}\n}\n\n  /*面包导航*/\n  .nav-toggle,a.nav-toggle{position:absolute; top:0px; right:15px; font-size: 20px; color:#999; padding:6px 11px;background-color:rgba(0,0,0,0.5);color:#fff;-webkit-tap-highlight-color: rgba(0,0,0,0);\n    -webkit-touch-callout: none;\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  .nav-toggle:hover,a.nav-toggle:hover{ text-decoration: none; color:#fff}\n\n/*2.1.9 版本之前的导航条代码*/\n.mainnav{z-index:1;background-color:#222}/*导航条背景*/\n.mainnav > ul{ font-size: 0; line-height: 0}\n.mainnav > ul > li,\n.mainnav > ul > li > a{height:40px;line-height:40px}/*导航条高度*/\n.mainnav > ul > li{display:inline-block;color:#fff;font-size:14px;font-weight:bold}/*设置字体*/\n.mainnav > ul > li > a{display:inline-block;padding:0 20px;color:#fff;text-align:center}/*链接颜色*/\n.mainnav > ul > li > a:hover,\n.mainnav > ul > li.current > a{color:#fff;text-decoration:none; background-color:#000;-webkit-transition: background-color 0.3s ease 0s; -moz-transition: background-color 0.3s ease 0s; -o-transition: background-color 0.3s ease 0s; -ms-transition: background-color 0.3s ease 0s;transition: background-color 0.3s ease 0s}/*交互颜色*/\n\n.Hui-nav-toggle,a.Hui-nav-toggle{position:absolute; top:0px; right:15px; font-size: 20px; color:#999; padding:6px 11px;background-color:rgba(0,0,0,0.5);color:#fff}\n.Hui-nav-toggle:hover,a.Hui-nav-toggle:hover{ text-decoration: none; color:#fff}\n@media (max-width: 767px) {\n\t.mainnav > ul > li{font-size:1.125em}\n}\n@media (max-width: 480px) {\n\t.mainnav > ul > li{text-align:center}\n\t.mainnav > ul > li{width:20%}\n\t.mainnav > ul > li > a{padding:0;padding:0;display:block}\n}\n/*4.2.2 面包屑导航\n\tName:\t\t\tmod_breadcrumb\n\tExample:\n<nav class=\"breadcrumb\">\n  <div class=\"container\">\n    <i class=\"Hui-iconfont\">&#xe67f;</i> <a href=\"/\" class=\"c-primary\">首页</a><span class=\"c-gray en\">&gt;</span><a href=\"#\">组件</a><span class=\"c-gray en\">&gt;</span><span class=\"c-gray\">当前页面</span>\n  </div>\n</nav>\n*/\n.breadcrumb{border-bottom: 1px solid #E5E5E5;line-height: 39px; height:39px;overflow:hidden}\n.breadcrumb span{padding:0 5px}\n@media (max-width: 767px) {\n  .breadcrumb > .container{padding: 0}\n}\n/*4.2.3 翻页导航\n\tName:\t\t\tmod_pageNav\n\tExample:\t\t<div class=\"pageNav\" id=\"pageNav\"></div>\n\tExplain:\t\t需要调用pagenav.cn.js\n\n*/\n.pageNav{float:none;clear:both;font-size:0;font-family:Arial,Helvetica,sans-serif;padding:18px 0;text-align:center}\n.pageNav span,.pageNav a,.pageNav b{font-size:14px;margin-right:5px;overflow:hidden;padding:3px 8px}\n.pageNav a{border:1px solid #CCDBE4;cursor:pointer}\n.pageNav b{color:#000}\n.pageNav .mor{padding:3px;font-weight:bold}\n\n/*4.2.4 顶部导航\n\tName:\t\t\tmod_topnav\n\tSample:\n\t<div class=\"topnav\"><div class=\"cl\"><div class=\"l\">您好，欢迎来到Hui！</div><div class=\"r\"><span class=\"r_nav\">[ <a rel=\"nofollow\" href=\"javascript:login();\">登录</a> ]</span><span class=\"pipe\">|</span><span class=\"r_nav\">[ <a href=\"javascript:register();\" rel=\"nofollow\">注册</a> ]</span><span class=\"pipe\">|</span><span class=\"r_nav\"><a title=\"收藏\" href=\"javascript:addFavorite();\">收藏本站</a></span><span class=\"pipe\">|</span><span class=\"r_nav\"><a href=\"javascript:void(0)\" onclick=\"setHome(this);\" title=\"设为首页\">设为首页</a></span></div></div></div>\n\n*/\n.topnav{height:30px;line-height:30px;background-color;#f7f7f7;border-bottom:1px solid #EBEBEB; font-size:12px}\n.topbar{background-color: #ECECEC;border-bottom:1px solid #ddd}\n.topbar a{margin-right:5px}\n.r_nav{display:inline-block; color:#999}\n\n/*4.2.5 向导\n\tName:\t\t\tmod_steps\n\tSample:\n\t<div class=\"four steps\">\n\t  <span class=\"step\">第一步</span>\n\t  <span class=\"active step\">第二步</span>\n\t  <span class=\"disabled step\">第三步</span>\n\t  <span class=\"disabled step\">第四步</span>\n\t</div>\n*/\n.steps,.step{display:inline-block;position:relative;padding:1em 2em 1em 3em;vertical-align:top;background-color:#FFF;color:#888;\n\t-webkit-box-sizing:border-box;\n\t-moz-box-sizing:border-box;\n\t-ms-box-sizing:border-box;\n\tbox-sizing:border-box\n}\n.step:after,.steps .step:after{position:absolute;z-index:2;content:'';top:0;right:-1.45em;border-bottom:1.5em solid transparent;border-left:1.5em solid #FFF;border-top:1.5em solid transparent;width:0;height:0}\n.step,.steps .step,.steps .step:after{\n\t-webkit-transition:opacity .1s ease,color .1s ease,-webkit-box-shadow .1s ease;\n\ttransition:opacity .1s ease,color .1s ease,box-shadow .1s ease\n}\n.steps{cursor:pointer;display:inline-block;font-size:0;box-shadow:0 0 0 1px rgba(0,0,0,.1);border-radius:.3125rem;line-height:1;\n\t-webkit-box-sizing:border-box;\n\t-moz-box-sizing:border-box;\n\t-ms-box-sizing:border-box;\n\tbox-sizing:border-box}\n.steps .step:first-child{padding-left:1.35em;border-radius:.3125em 0 0 .3125em}\n.steps .step:last-child{border-radius:0 .3125em .3125em 0}\n.steps .step:only-child{border-radius:.3125em}\n.steps .step:last-child{margin-right:0}\n.steps .step:last-child:after{display:none}\n.step:hover,.step.hover{background-color:#F7F7F7;color:rgba(0,0,0,.8)}\n.steps .step.hover:after,\n.steps .step:hover:after,\n.step:hover,\n.step.hover::after{border-left-color:#F7F7F7}\n.steps .step.down,\n.steps .step:active,\n.step.down,\n.step:active{background-color:#F0F0F0}\n.steps .step.down:after,\n.steps .step:active:after,\n.steps.down::after,\n.steps:active::after{border-left-color:#F0F0F0}\n.steps .step.active,\n.active.step{cursor:auto;background-color:#428BCA;color:#FFF;font-weight:700}.steps .step.active:after,.active.steps:after{border-left-color:#428BCA}\n.steps .disabled.step,\n.disabled.step{cursor:auto;background-color:#FFF;color:#CBCBCB}\n.disabled.step:after{border:0;background-color:#FFF;top:.42em;right:-1em;width:2.15em;height:2.15em;\n\t-webkit-transform:rotate(-45deg);\n\t-ms-transform:rotate(-45deg);\n\ttransform:rotate(-45deg);\n\tbox-shadow:-1px -1px 0 0 rgba(0,0,0,.1) inset\n}\n.attached.steps{margin:0;border-radius:.3125em .3125em 0 0}\n.attached.steps .step:first-child{border-radius:.3125em 0 0}\n.attached.steps .step:last-child{border-radius:0 .3125em 0 0}\n.bottom.attached.steps{margin-top:-1px;border-radius:0 0 .3125em .3125em}\n.bottom.attached.steps .step:first-child{border-radius:0 0 0 .3125em}\n.bottom.attached.steps .step:last-child{border-radius:0 0 .3125em}\n\n/*向导数量*/\n.one.steps,.two.steps,.three.steps,.four.steps,.five.steps,.six.steps,.seven.steps,.eight.steps{display:block}\n.one.steps > .step{width:100%}\n.two.steps > .step{width:50%}\n.three.steps > .step{width:33.333%}\n.four.steps > .step{width:25%}\n.five.steps > .step{width:20%}\n.six.steps > .step{width:16.666%}\n.seven.steps > .step{width:14.285%}\n.eight.steps > .step{width:12.5%}\n\n/*向导尺寸*/\n.small.step,.small.steps .step{font-size:.8rem}/*小*/\n.step,.steps .step{font-size:1rem}/*默认*/\n.large.step,.large.steps .step{font-size:1.25rem}/*大*/\n\n/*兼容写法\n\tSample:\n\t<div class=\"steps-ie cl\">\n\t  <a class=\"step-ie active\" href=\"#\">第一步<em class=\"arrow\"></em></a>\n\t  <a class=\"step-ie\" href=\"#\">第二步<em class=\"arrow\"></em></a>\n\t  <a class=\"step-ie\" href=\"#\">第三步<em class=\"arrow\"></em></a>\n\t</div>\n*/\n.steps-ie,.step-ie,.step-ie .arrow{height:44px; line-height:44px}\n.steps-ie{background-color:#eaf4fd; border:solid 1px #afcfcc}\n.step-ie{position:relative;display:inline-block; float:left; cursor:pointer; padding:0 20px 0 40px; background:url(../images/steps/step_bg.png) repeat-x 0 center}\n.step-ie .arrow{position:absolute;right:-21px; top:0; width:21px; height:44px; display:block; cursor:pointer; background:url(../images/steps/step_arrow.png) no-repeat 0 center;z-index:50}\n.step-ie.active{background-image:url(../images/steps/step_bg-active.png); color:#fff; z-index:100}\n.step-ie.active .arrow{background-image:url(../images/steps/step_arrow-active.png)}\n\n/*4.2.6 竖向导向tab导航\n\tSample:\n\t<div class=\"verticalTab\">\n\t  <a class=\"\" href=\"#\">导航一<em></em></a>\n\t  <a class=\"active\" href=\"#\">导航二<em></em></a>\n\t  <a href=\"#\">导航三<em></em></a>\n\t  <a href=\"#\">导航四<em></em></a>\n\t</div>\n*/\n.verticalTab{background:#fff url(../images/verticalTab/tab_bg.png) repeat-y 0 0; width:38px}\n.verticalTab a{position:relative; display:block; width:18px; height:auto; text-align:center; position:relative; padding:26px 10px 6px 10px; background:url(../images/verticalTab/tabNav.png) no-repeat 0 0}\n.verticalTab a em{position:absolute; left:0; bottom:-20px; width:38px; height:20px; background:url(../images/tabNav_right.png) no-repeat 0 0; z-index:50}\n.verticalTab a.active{background-image:url(../images/verticalTab/tabNav-active.png); color:#fff; z-index:99}\n.verticalTab a.active em{background-image:url(../images/verticalTab/tabNav_right-active.png)}\n\n/*4.2.6 横向导向tab导航\n\tSample:\n\t<ul class=\"acrossTab\">\n\t  <li>导航一<i></i><em></em></li>\n\t  <li class=\"active\">导航二<i></i><em></em></li>\n\t  <li>导航三<i></i><em></em></li>\n\t</ul>\n*/\n.acrossTab,.acrossTab li,.acrossTab li em{ background-image:url(../images/acrossTab/acrossTab-bg.png)}\n.acrossTab{height:29px; background-repeat: repeat-x; background-position: 0 0; padding-top:1px}\n.acrossTab li,.acrossTab li em{ background-repeat:no-repeat; background-position:0 0}\n.acrossTab li{position:relative;float:left; display:inline-block; height:29px; line-height:29px; font-size:12px;cursor:pointer;padding:0 30px; white-space:nowrap;color:#282828; background-position:0 0}\n.acrossTab li em{position:absolute; width:23px;height:29px;right:-20px; top:0;z-index:50; background-position:right -30px}\n.acrossTab li:hover{background-position:0 -60px}\n.acrossTab li:hover em{background-position:right -90px}\n.acrossTab li.active{background-position:0 -120px; z-index:99}\n.acrossTab li.active em{background-position:right -150px}\n.acrossTab li i{position:absolute; display:block; width:13px; height:13px; top:50%; margin-top:-6px; right:5px; font-size:0; line-height:0; cursor:pointer; background-image:url(../images/acrossTab/acrossTab-close.png); background-repeat:no-repeat; background-position:0 0}\n.acrossTab li i:hover{background-position:0 bottom}\n\n/*4.3.1 下拉菜单\n\tName:\t\t\tmod_dropDown\n\tExample:\n\t<span class=\"dropDown\">\n\t\t<a class=\"dropDown_A\" href=\"#\">下拉菜单</a>\n\t\t<ul class=\"dropDown-menu menu radius box-shadow\">\n\t\t\t<li><a href=\"#\">菜单一</a></li>\n\t\t\t<li><a href=\"#\">菜单二</a></li>\n\t\t</ul>\n\t</span>\n\tExplain:\t\t如需要在不同的地方显示不同的样式，请在<span class=\"dropDown\"> 追加class，采用覆盖的方式重写默认样式。\n\n*/\n.dropDown{display:inline-block}\n.dropDown_A{display:inline-block}\n.dropDown-menu{ display:none;transition: all 0.3s ease 0s}\n.dropDown:focus,.dropDown-menu:focus {outline:0}\n.dropDown-menu li.arrow{ position:absolute;display:block; width:12px; height:8px; margin-top:-13px; margin-left:20%; line-height:0;background:url(../images/dropDown/icon-jt.png) no-repeat 0 0}\n/*鼠标经过*/\n.dropDown.hover .dropDown_A,\n.dropDown.open .dropDown_A{text-decoration:none;background-color:rgba(255,255,255,0.2)}\n.dropDown.open .dropDown_A .menu_dropdown-arrow{transition-duration:0.3s ;transition-property:all;_background-position:0 0;transform: rotate(180deg)}\n\n.menu{background-color:#fff;border:solid 1px #f2f2f2; display: inline-block}\n.menu.radius{border-top-left-radius:0;border-top-right-radius:0}\n.menu.box-shadow{border-top:none}\n.menu > li{position:relative; clear:both;* float:left}\n.menu > li > a{ display: block;border-bottom:solid 1px #f2f2f2;padding:5px 20px; line-height:1.8;text-align:left;font-weight: normal;white-space:nowrap; vertical-align:top}\n.menu > li:last-child > a{ border-bottom:none}\n.menu > li > a:hover,.menu > li > a:focus,.menu > li.open > a{ text-decoration:none;background-color:#fafafa}\n.menu > li > a .arrow{ position:absolute; top:50%; margin-top:-10px; right:5px;line-height: 20px; height: 20px; color: #999}\n.menu > li > .menu{ display: none}\n.menu > li.open > .menu{ display: inline-block;position: absolute; left:100%;top:-1px;min-width:100%}\n\n/*禁用菜单*/\n.menu > li.disabled > a{color:#999;text-decoration:none; cursor:no-drop; background-color:transparent}\n/*线条*/\n.menu > li.divider{ display:block;height:0px; line-height:0px;margin:9px 0;overflow:hidden; border-top:solid 1px #eee}\n\n/*打开菜单*/\n.dropDown > .dropDown-menu{ display: none}\n.dropDown.open{position:relative;z-index:990}\n/*默认左对齐*/\n.dropDown.open > .dropDown-menu{position:absolute;z-index:1000;display:inline-block;top:100%;left:-1px;min-width:100%;background-color:#fff;border:solid 1px #f2f2f2}\n/*右对齐*/\n.dropDown.open.right > .dropDown-menu{right:-1px!important;left:auto!important}\n\n/*4.4 幻灯片\n\tName:\t\t\tmodule_slider\n\tSample:\n<div id=\"slider-1\">\n  <div class=\"slider\">\n    <div class=\"bd\">\n      <ul>\n        <li><a href=\"http://www.h-ui.net/\" target=\"_blank\"><img src=\"temp/banner1.jpg\" ></a></li>\n        <li><a href=\"http://www.h-ui.net/zhaishang.shtml\" target=\"_blank\"><img src=\"temp/banner2.jpg\" ></a></li>\n        <li><a href=\"http://h-ui.net/H-ui.admin.shtml\" target=\"_blank\"><img src=\"temp/banner4.jpg\" ></a></li>\n      </ul>\n    </div>\n    <ol class=\"hd cl dots\">\n      <li>1</li>\n      <li>2</li>\n      <li>3</li>\n    </ol>\n  </div>\n</div>\n\t<script type=\"text/javascript\" src=\"lib/jquery.SuperSlide/2.1.1/jquery.SuperSlide.min.js\"></script>\n\t<script type=\"text/javascript\">\n\t$(function() {\n\t\tjQuery(\"#slider-1 .slider\").slide({mainCell:\".bd ul\",titCell:\".hd li\",trigger:\"click\",effect:\"leftLoop\",autoPlay:true,delayTime:700,interTime:3000,pnLoop:false,titOnClassName:\"active\"});\n\t});\n\t</script>\n\tExplain: 默认dots为圆点，在slider后面追加numSlider样式就变成带数字的方框，boxSlider为不带数字长方条\n*/\n.slider{position:relative;text-align:center; margin:0 auto;z-index:1}\n.slider .bd,.slider .bd li,.slider .bd img{width:100%; height:100%}/*请给每个幻灯片套个div并设置id，通过id重置这个地方的宽度，达到自定义效果*/\n.slider .bd{z-index:2;overflow:hidden}\n.slider .bd li{float:left;width: 100%;overflow:hidden; background-position:center; background-repeat:no-repeat}\n.slider .bd li a{ display:block; width: 100%; height: 100%}\n.slider .bd li img{display:block}\n.slider .hd{ position: absolute; z-index: 3; left: 0; right: 0; bottom:10px; padding: 0 10px; text-align: center}\n.slider .hd li{display:inline-block;text-align:center;margin-right:10px;cursor:pointer;background-color:#C2C2C2}\n.slider .hd li.active{background-color:#222}\n\t/*圆点*/\n\t.dots li{width:10px; height:10px;font-size:0px;line-height:0px;border-radius:50%}\n\t/*数字*/\n\t.numbox li{width:20px; height:20px; line-height:20px; font-size:13px;font-family:Arial;font-weight:bold; text-indent:inherit}\n\t.numbox li.active{color:#fff}\n\t/*长方条*/\n\t.rectangle li{width:40px; height:10px;font-size:0px;line-height:0px}\n\n.slider-arrow{display:block; position:absolute; top:50%; margin-top:-25px;height: 50px;width: 50px; line-height: 50px; text-align: center; z-index:3;opacity: 0.7;filter: alpha(opacity=70)}\n.slider-arrow:hover{opacity: 1;filter: alpha(opacity=100)}\n.slider-arrow.prev{left:0px}\n.slider-arrow.next{right:0px}\n\n/*4.5 选项卡\n\tName:\t\t\tmodule_slider\n\tSample:\n\t<div id=\"tab_demo\" class=\"HuiTab\">\n      <div class=\"tabBar cl\"><span>选项卡一</span><span>选项卡二</span><span>自适应宽度</span></div>\n      <div class=\"tabCon\">内容一</div>\n      <div class=\"tabCon\">内容二</div>\n      <div class=\"tabCon\">内容三</div>\n    </div>\n*/\n.tabBar {border-bottom: 2px solid #222}\n.tabBar span {background-color: #e8e8e8;cursor: pointer;display: inline-block;float: left;\nfont-weight: bold;height: 30px;line-height: 30px;padding: 0 15px}\n.tabBar span.current{background-color: #222;color: #fff}\n.tabCon {display: none}\n\n/*4.6 标签与标号\n\tName:\t\t\tstyle_label\n\tExample:\t\t<span class=\"label label-default|label-primary|label-secondary|label-success|label-warning|label-danger\">默认</span>\n\tExplain:\t\t.label-default 默认|.label-primary 主要|.label-secondary 次要|.label-success 成功|.label-warning 警告|.label-danger 危险\n\n\tName:\t\t\tstyle_badge\n\tExample:\t\t<span class=\"badge badge-default|label-primary|badge-secondary|badge-success|badge-warning|badge-danger\">默认</span>\n\tExplain:\t\t.badge-default 默认|.badge-primary 主要|.badge-secondary 次要|.badge-success 成功|.badge-warning 警告|.badge-danger 危险\n\n*/\n.label, .badge{display: inline-block;padding:2px 4px;font-size: 11.844px;font-weight: bold;line-height:14px;color: #fff;white-space: nowrap;vertical-align:middle;background-color: #999; overflow: hidden}\n/*圆角*/\n.label.radius{border-radius: 3px}\n.badge{padding-right:9px;padding-left:9px;border-radius:9px}\n.label:empty, .badge:empty{display: none}\na.label:hover, a.label:focus, a.badge:hover, a.badge:focus{color: #fff;text-decoration: none;cursor: pointer}\n\n/*默认*/\n.label-default, .badge-default{background-color: #e6e6e6; color:#333}\n.label-default[href], .badge-default[href]{background-color: #e6e6e6;color:#333}\n\n/*主要*/\n.label-primary, .badge-primary{background-color: #5a98de}\n.label-primary[href], .badge-primary[href]{background-color: #5a98de}\n\n/*主要*/\n.label-secondary, .badge-secondary{background-color: #3bb4f2}\n.label-secondary[href], .badge-secondary[href]{background-color: #3bb4f2}\n\n/*成功*/\n.label-success, .badge-success{background-color:#5eb95e}\n.label-success[href], .badge-success[href]{background-color: #5eb95e}\n\n/*警告*/\n.label-warning, .badge-warning{background-color: #f37b1d}\n.label-warning[href], .badge-warning[href]{background-color: #f37b1d}\n\n/*危险*/\n.label-danger, .badge-danger{background-color: #dd514c}\n.label-danger[href], .badge-danger[href]{background-color: #dd514c}\n\n/*4.7 缩略图\n\tName:       style_img\n\tExample:\n\tExplain:\t\t缩略图 删除，转移到3.6 图片中\n*/\n\n/*4.8 警告\n\tName:\t\t\tmod_Hui-alert\n\tExample:\n<div class=\"Huialert Huialert-success/Huialert-danger/Huialert-error/Huialert-info/Huialert-block\">\n\t<i class=\"Hui-iconfont\">&#xe6a6;</i>\n\t警告内容\n\t<ul>\n\t\t<li>……</li>\n\t</ul>\n</div>\n\tExplain:\t\t警告,使用警告框jQuery插件\n*/\n.Huialert{position:relative;padding:8px 35px 8px 14px;margin-bottom: 20px;text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);background-color: #fcf8e3;border: 1px solid #fbeed5}\n.Huialert, .Huialert h4{color: #c09853}\n.Huialert h4{margin: 0}\n.Huialert .Hui-iconfont{position:absolute;top:9px;right:10px;line-height: 20px;cursor:pointer; color:#000; opacity:0.2;_color:#666}\n.Huialert .Hui-iconfont.hover{color:#000;opacity:0.8}\n.Huialert-success{color: #468847;background-color: #dff0d8;border-color: #d6e9c6}\n.Huialert-success h4{color: #468847}\n.Huialert-danger{color: #b94a48;background-color: #f2dede;border-color: #eed3d7}\n.Huialert-danger h4{color: #b94a48}\n.Huialert-error{color: #fff;background-color: #f37b1d;border-color: #e56c0c}\n.Huialert-error h4{color: #fff}\n.Huialert-info{color: #31708f;background-color: #d9edf7;border-color: #bce8f1}\n.Huialert-info h4{color:#31708f}\n.Huialert-block{padding-top: 14px;padding-bottom: 14px}\n.Huialert-block > p,.Huialert-block > ul{margin-bottom: 0}\n.Huialert-block p + p{margin-top: 5px}\n\n/*4.9 进度条 loading\n\tName:\t\t\tmod_progress\n\tExample:\n\t<div class=\"progress radius\"><div class=\"progress-bar\"><span class=\"sr-only\"></span></div></div>\n\tExplain:\t\t警告,使用警告框jQuery插件\n*/\n.progress,.progress-bar,.sr-only{height:10px; font-size:0;line-height:0}\n.progress{overflow:hidden; width:400px}\n.progress.radius{}/*自定义圆角*/\n.progress-bar{width:100%;background-color:#efefef;}\n.sr-only{\n\tdisplay:inline-block; background-color:#337ab7;\n\t-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-bar-success .sr-only{ background-color:#5cb85c}\n.progress-bar-warning .sr-only{background-color: #f0ad4e}\n.progress-bar-danger .sr-only{background-color: #d9534f}\n\n/*4.10 对话框\n\tName:\t\t\tmod_modal\n\tExample:\n<div id=\"modal-demo\" class=\"modal fade\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"myModalLabel\" aria-hidden=\"true\">\n\t<div class=\"modal-dialog\">\n\t\t<div class=\"modal-content\">\n\t\t\t<div class=\"modal-header\">\n\t\t\t\t<h3 id=\"myModalLabel\">对话框标题</h3>\n\t\t\t\t<a class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\" href=\"javascript:void();\">×</a>\n\t\t\t</div>\n\t\t\t<div class=\"modal-body\">\n\t\t\t\t<p>对话框内容…</p>\n\t\t\t</div>\n\t\t\t<div class=\"modal-footer\">\n\t\t\t\t<button class=\"btn btn-primary\">确定</button> <button class=\"btn\" data-dismiss=\"modal\" aria-hidden=\"true\">关闭</button>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n*/\n.fade {opacity: 0;\n  -webkit-transition: opacity .15s linear;\n       -o-transition: opacity .15s linear;\n          transition: opacity .15s linear}\n.fade.in {opacity: 1}\n.modal-open {overflow: hidden}\n.modal{ position:fixed; left:0; top:0; right:0; bottom:0; z-index:1040; display:none; overflow:hidden;-webkit-overflow-scrolling:touch; outline:0}\n.modal.fade .modal-dialog{\n\t-webkit-transition: -webkit-transform .3s ease-out;\n\t\t -o-transition: -o-transform .3s ease-out;\n\t\t\ttransition: transform .3s ease-out;\n\t-webkit-transform: translate(0,-50%);\n\t\t-ms-transform: translate(0,-50%);\n\t\t -o-transform: translate(0,-50%);\n\t\t\ttransform: translate(0,-50%)}\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.modal-open .modal {overflow-x: hidden;overflow-y: auto}\n\t.modal-backdrop {position: fixed;top: 0;right: 0;bottom: 0;left: 0;background-color: #000}\n\t.modal-backdrop.fade {filter: alpha(opacity=0);opacity: 0}\n\t.modal-backdrop.in {filter: alpha(opacity=50);opacity: .5}\n\t.modal-dialog {position: relative;margin:10px}\n\t\t.modal-content{position: relative;background-color: #fff;border: 1px solid #999;border: 1px solid rgba(0,0,0,.2);outline: 0;\n    \t\t-webkit-background-clip: padding-box;\n\t\t\t\t\tbackground-clip: padding-box;\t\t\t\t\t\n\t\t\t-webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);\n\t\t\t\t\tbox-shadow: 0 3px 9px rgba(0,0,0,.5)}\n\t\t\n\t\t\t.modal-header {min-height: 16.42857143px;padding: 15px;border-bottom: 1px solid #eee; position:relative}\n\t\t\t.modal-header .close{position:absolute; right:15px; top:15px}\n\t\t\t.modal-close{position:absolute; right:15px; top:15px;font-size:24px; z-index: 9}\n\t\t\ta.modal-close:hover{ text-decoration: none}\n\t\t\t.modal-header h3,.modal-header .modal-title{margin:0; padding:10px 0; font-size:16px}\n\t\t\t\n\t\t\t.modal-body {position:relative;padding:15px;overflow-y:visible;word-break:break-all}\n\t\t\t\t.modal-form {margin-bottom: 0}\n\t\t\t\t\n\t\t\t.modal-footer {padding:15px;margin-bottom: 0;text-align: right;background-color: #f5f5f5;border-top: 1px solid #eee;*zoom: 1}\n\t\t\t\n\t\t\t.modal-footer:before,.modal-footer:after {display: table;content: \"\"}\n\t\t\t.modal-footer:after {clear: both}\n\t\t\t.modal-footer .btn + .btn {margin-left: 5px;margin-bottom: 0}\n\t\t\t.modal-footer .btn-group .btn + .btn {margin-left: -1px}\n\t\t\t.modal-footer .btn-block + .btn-block {margin-left: 0}\n\t\t.modal-scrollbar-measure {position: absolute;top: -9999px;width: 50px;height: 50px;overflow: scroll}\n\t\t\n\t\t.radius .modal-content{ border-radius:6px}\n\t\t.radius .modal-footer{ border-bottom-left-radius:6px; border-bottom-right-radius:6px}\n/*上下居中*/\n.modal.middle .modal-dialog{position:absolute;margin:10px;left:0;right:0;top:50%}\n.modal.fade.middle .modal-dialog{\n\t-webkit-transform: translate(0,-100%);\n\t\t-ms-transform: translate(0,-100%);\n\t\t -o-transform: translate(0,-100%);\n\t\t\ttransform: translate(0,-100%)}\n.modal.in.middle .modal-dialog{\n\t-webkit-transform:translate(0,-50%);\n\t-ms-transform:translate(0,-50%);\n\t-o-transform:translate(0,-50%);\n\ttransform:translate(0,-50%)\n}\n\n\n@media (min-width: 768px) {\n  .modal-dialog { width:600px;margin: 30px auto}\n  .modal.middle .modal-dialog{ margin:10px auto}\n  .modal-content {-webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);box-shadow: 0 5px 15px rgba(0, 0, 0, .5)}\n  .modal-sm {width: 300px}\n}\n@media (min-width: 992px) {\n  .modal-lg {width: 900px}\n}\n\n\n\t\n.modal-alert{position:fixed; right:auto; bottom:auto; width:300px; left:50%;margin-left:-150px; top:50%;margin-top:-30px; z-index:9999;background-color: #fff;border: 1px solid #999;border: 1px solid rgba(0,0,0,.2);outline: 0;\n-webkit-background-clip: padding-box;\n\t\tbackground-clip: padding-box;\t\t\t\t\t\n-webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);\n\t\tbox-shadow: 0 3px 9px rgba(0,0,0,.5)}\n\n\t.modal-alert-info{padding:30px; text-align:center; font-size:14px; background-color:#fff}\n\n\n.loading{height: 50px; width: 50px; background:#fff url(../images/loading/loading-b.gif) no-repeat center}\n.mask{position:fixed;top:0;left:0;z-index:999;width:100%;height:100%;background-color:rgba(0,0,0,0.7);-moz-transition:all 0.3s ease-in;-webkit-transition:all 0.3s ease-in;-o-transition:all 0.3s ease-in;transition:all 0.3s ease-in}\n* html .mask{position:absolute;left:expression(documentElement.scrollLeft + documentElement.clientWidth - this.offsetWidth);top:expression(documentElement.scrollTop + documentElement.clientHeight - this.offsetHeight)}\n\n.mask_box{background-image:none;display:none;z-index:99}\n.hover .mask_box{position:absolute;bottom:0; left:0;display:block;background-color:rgba(0,0,0,0.3);text-align:left}\n.modal-open .dropdown-menu {z-index: 2050}\n.modal-open .dropdown.open {*z-index: 2050}\n.modal-open .popover {z-index: 2060}\n.modal-open .tooltip {z-index: 2070}\n\t\t\n/*\t//old 版本\n\n\t//当弹出层出现时，隐藏body右侧滚动条\n\t.modal-open{overflow-x: hidden;overflow-y: auto}\n\t//隐藏body滚动条时，页面偏移\n\t.page-overflow{margin-right:16px}\n\t//弹出层，绝对定位，默认【宽度500px，高度自适应，背景白色，6px圆角，带阴影】，自定义宽度可在data-width中设置参数\n\t.modal {position:absolute;top:50%;left:50%; width:500px;margin-left:-250px;z-index:1050;overflow: visible;background-color: #fff;background-clip: padding-box;\n\t\tbox-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n\t\t-webkit-background-clip:padding-box;\n\t\t-khtml-background-clip:padding-box;\n\t\t-moz-background-clip:padding-box;\n\t\t-ms-background-clip:padding-box;\n\t\t-o-background-clip:padding-box;\n\t\tbackground-clip:padding-box;\n\t\tborder-radius:6px;\n\t\tborder:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999}\n\n\t//弹出层进入动画效果\n\t.modal.fade {top: -100%}\n\t//弹出层进入后居顶距离，配合margin-top负值，实现上下自动居中\n\t.modal.fade.in{top:50%}\n\t//如果弹出层高度大于窗口，弹出窗口距顶0像素\n\t.modal.modal-overflow.fade.in{top:0}\n\t\n\t//隐藏body滚动条时，页面偏移\n\t.page-overflow{margin-right:16px}\n\t\n\t//弹出层的最外层，全屏，用户响应点击和滚动\n\t.modal-scrollable{position:fixed;top:0;right:0;bottom:0;left:0;overflow: auto}\n\t\n\t//弹窗超出屏幕高度时，弹出层替代body右侧滚动条，实现弹出层的整体滚动\n\t.modal-overflow .modal-scrollable{overflow-y:scroll}\n\t\n\t//默认遮罩层，全屏黑色\n\t.modal-backdrop {position:fixed;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:1040;background-color:#000}\n\t//解决IE下 遮罩层兼容性\n\t* html .modal-backdrop{position:absolute;left:expression(documentElement.scrollLeft + documentElement.clientWidth - this.offsetWidth);top:expression(documentElement.scrollTop + documentElement.clientHeight - this.offsetHeight)}\n\t\n\t//遮罩层失去时，透明度为0\n\t.modal-backdrop.fade {opacity:0;filter: alpha(opacity=0)}\n\t\n\t//遮罩层进入 0.7透明度\n\t.modal-backdrop,.modal-backdrop.fade.in {opacity: 0.7;filter: alpha(opacity=70)}\n\t\n\t//Ajax加载数据时loading\n\t.loading-spinner {position: absolute;top: 50%;left: 50%;margin: -12px 0 0 -12px}\n\t\n\t//弹出层header区\n\t//弹出层头部\n\t.modal-header {padding: 9px 15px;border-bottom: 1px solid #eee; position:relative}\n\t//关闭按钮，请调用4.1.1 按钮 .close\n\t.modal-header .close{position:absolute; right:10px; top:10px}\n\t//标题\n\t.modal-header h3{margin:0; padding:10px 0; font-size:16px}\n\t\n\t//内容不限高度，内填充15px，不满意可自行修改\n\t.modal-body {overflow-y:visible;padding: 15px; word-break:break-all}\n\t//弹出层表单\n\t.modal-form {margin-bottom: 0}\n\t//弹出层footer区，放按钮\n\t.modal-footer {padding: 14px 15px 15px;margin-bottom: 0;text-align: right;background-color: #f5f5f5;border-top: 1px solid #ddd;*zoom: 1;border-radius: 0 0 6px 6px;box-shadow: inset 0 1px 0 #fff}\n\t.modal-footer:before,.modal-footer:after {display: table;content: \"\"}\n\t.modal-footer:after {clear: both}\n\t.modal-footer .btn + .btn {margin-left: 5px;margin-bottom: 0}\n\t.modal-footer .btn-group .btn + .btn {margin-left: -1px}\n\t.modal-alert{position:fixed; width:300px;margin-left:-150px; margin-top:-30px; z-index:9999}\n\t.modal-alert-info{padding:30px; text-align:center; font-size:14px; background-color:#fff}*/\n\n/*.easyDialog_wrapper{width:320px; color:#444; border:3px solid rgba(0,0,0,0);border-radius:5px;box-shadow:0 0 10px rgba(0,0,0,0.4); display:none}\n.easyDialog_wrapper .easyDialog_content{border-radius:4px; background:#fff; border:1px solid #e5e5e5}\n.easyDialog_wrapper .easyDialog_title{height:30px; line-height:30px; overflow:hidden; color:#666; padding:0 10px; font-size:14px; border-bottom:1px solid #e5e5e5; background:#f7f7f7; border-radius:4px 4px 0 0; margin:0 }\n.easyDialog_wrapper .close_btn{font-family:arial; font-size:18px; _font-size:12px; font-weight:700; color:#999; text-decoration:none; float:right}\n.easyDialog_wrapper .close_btn:hover{color:#333}\n.easyDialog_wrapper .easyDialog_text{padding:25px 10px; font-size:13px; line-height:22px}\n.easyDialog_wrapper .easyDialog_footer{padding:10px; text-align:right; *zoom:1}\n.easyDialog_wrapper .easyDialog_footer:after{content:''; display:block; height:0; overflow:hidden; visibility:hidden; clear:both}\n.easyDialog_wrapper .btn_highlight,.easyDialog_wrapper .btn_normal{border:1px solid; border-radius:2px; cursor:pointer;float:right; font-size:12px; padding:0 12px; height:24px; line-height:24px; margin-bottom:10px}\n.easyDialog_wrapper .btn_highlight{background:#4787ed; background:-webkit-gradient(linear,center bottom,center top,from(#4787ed),to(#4d90fe)); background:-moz-linear-gradient(90deg, #4787ed, #4d90fe); border-color:#3079ed; color:#fff}\n.easyDialog_wrapper .btn_normal{margin-left:10px; border-color:#c3c3c3; background:#ececec; color:#333; background:-webkit-gradient(linear,center bottom,center top,from(#ececec),to(#f4f4f4)); background:-moz-linear-gradient(90deg,#ececec,#f4f4f4)}*/\n\n/*4.12 右侧悬浮工具\n\tName:\t\tmodal_tools-right\n*/\n.tools-right{position:fixed;right:15px;z-index:999;cursor: pointer;visibility:visible; background-color:#fff;border: 1px solid #d9d9d9;color: #9c9c9c;font-size: 16px;width: 38px;height: 38px;line-height: 38px;text-align: center; text-decoration:none;_position:absolute;_top:expression(documentElement.scrollTop + documentElement.clientHeight-this.offsetHeight)}\n.tools-right:hover{color:#fff; text-decoration:none; background-color:#999; border-color:#999}\n\t/*4.12.1 返回顶部\n\t\tName:\t\t\tmod_totop\n\t\tLevel:\t\t\tGlobal\n\t\tExample:\t\t<a href=\"javascript:void(0)\" class=\"tools-right toTop\" title=backToTopTxt alt=backToTopTxt></a>\n\t\tExplain:\t\t返回顶部\n\t*/\n\t.tools-right.toTop{bottom:60px;display:none}\n\t/*4.12.2 意见反馈\n\t\tName:\t\t\tmod_feedback\n\t\tLevel:\t\t\tGlobal\n\t\tExample:\t\t<a href=\"javascript:;\" class=\"tools-right feedback Hui-iconfont\" title=\"意见反馈\" onClick=\"feedback()\">&#xe70c;</a>\n\t\tExplain:\t\t意见反馈\n\t<div id=\"modal-feedback\" class=\"modal hide fade\">\n\t\t<div class=\"modal-header\">\n\t\t\t <h3>意见反馈</h3>\n\t\t\t <a class=\"Hui-iconfont close\" data-dismiss=\"modal\" aria-hidden=\"true\" href=\"javascript:void();\">&#xe6a6;</a>\n\t\t</div>\n\t\t<div class=\"modal-body\">\n\t\t\t<div>\n\t\t\t\t<label class=\"mr-20\"><input type=\"radio\" class=\"radio\" value=\"1\" name=\"radio-feedback\" id=\"feedback-1\"> 业务咨询</label>\n\t\t\t\t<label class=\"mr-20\"><input type=\"radio\" class=\"radio\" value=\"2\" name=\"radio-feedback\" id=\"feedback-2\"> 体验反馈</label>\n\t\t\t\t<label class=\"mr-20\"><input type=\"radio\" class=\"radio\" value=\"3\" name=\"radio-feedback\" id=\"feedback-3\"> 好点子</label>\n\t\t\t</div>\n\t\t\t<div class=\"formControls mt-20\">\n\t\t\t\t<textarea class=\"textarea valid\" onKeyUp=\"$.Huitextarealength(this,500)\" placeholder=\"吐槽点什么...最少输入10个字符\"></textarea>\n\t\t\t\t<p class=\"textarea-numberbar\"><em class=\"textarea-length\">0</em>/500</p>\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"modal-footer\">\n\t\t\t<button class=\"btn btn-primary radius\">确定</button>\n\t\t\t<button class=\"btn btn-default radius ml-10\" data-dismiss=\"modal\" aria-hidden=\"true\">取消</button>\n\t\t</div>\n\t</div>\n\t*/\n\t.tools-right.feedback{ bottom:110px}\n\n/*4.13 分享到\n\tName:\t\t\tmod_share\n\tExample:\n\tExplain:\t分享到\n*/\n\t/*4.13.1 百度分享*/\n\t.bdsharebuttonbox.Hui-share a.bds_more,\n\t.bdsharebuttonbox.Hui-share a.bds_weixin,\n\t.bdsharebuttonbox.Hui-share a.bds_qzone,\n\t.bdsharebuttonbox.Hui-share a.bds_sqq,\n\t.bdsharebuttonbox.Hui-share a.bds_tsina,\n\t.bdsharebuttonbox.Hui-share a.bds_tqq,\n\t.bdsharebuttonbox.Hui-share a.bds_douban{ display:inline-block; background:none;padding-left:0; text-decoration:none; margin:0; margin-right:6px; height:auto; line-height:auto}\n\t.bdsharebuttonbox.Hui-share a:hover{ text-decoration:none}\n\t.bdsharebuttonbox.Hui-share .share-text{ display:inline-block; margin-right:6px; color:#999; cursor:default;float:left}\n\t\n\t.bdsharebuttonbox.bdshare-button-style0-16.Hui-share a,\n\t.bdsharebuttonbox.bdshare-button-style0-16.Hui-share .share-text,\n\t.bdsharebuttonbox.bdshare-button-style0-16.Hui-share .Hui-iconfont{line-height:16px}\n\t.bdsharebuttonbox.bdshare-button-style0-16.Hui-share .share-text,\n\t.bdsharebuttonbox.bdshare-button-style0-16.Hui-share .Hui-iconfont{font-size:16px}\n\t\n\t.bdsharebuttonbox.bdshare-button-style0-24.Hui-share a,\n\t.bdsharebuttonbox.bdshare-button-style0-24.Hui-share .share-text,\n\t.bdsharebuttonbox.bdshare-button-style0-24.Hui-share .Hui-iconfont{line-height:24px}\n\t.bdsharebuttonbox.bdshare-button-style0-24.Hui-share .share-text,\n\t.bdsharebuttonbox.bdshare-button-style0-24.Hui-share .Hui-iconfont{font-size:24px}\n\t/*4.13.2 jiathis分享*/\n\t.Hui-share.jiathis_style_24x24 .jtico{ background:none; padding-left:0!important}\n\t.Hui-share.jiathis_style_24x24 .jiathis_separator{ margin-left:0; margin-right:6px}\n/*4.14 Panel 面板\n\tName:\t\t\tmod_panel\n\tSample:\n\t<div class=\"panel panel-default\">\n\t\t<div class=\"panel-body\">默认面板</div>\n\t</div>\n*/\n.panel{ background-color:#fff; border:solid 1px transparent}\n\t.panel-header{ border-bottom:solid 1px transparent; padding:8px 15px; font-size:14px; font-weight:700; margin-bottom:-1px}/*面板标题*/\n\t.panel-body{ padding:15px}/*面板内容*/\n\t.panel-footer{background-color: #f5f5f5;border-top: 1px solid #ddd;padding:5px 20px}/*面板页脚*/\n/*默认面板*/\n.panel-default{border-color:#ddd}\n.panel-default > .panel-header{ border-color:#ddd; background-color:#f5f5f5; color:#444}\n\n/*主要面板*/\n.panel-primary{border-color:#5a98de}\n.panel-primary > .panel-header{ border-color:#5a98de; background-color:#5a98de; color:#fff}\n\n/*次要面板*/\n.panel-secondary{border-color:#3bb4f2}\n.panel-secondary > .panel-header{ border-color:#3bb4f2; background-color:#3bb4f2; color:#fff}\n\n/*成功面板*/\n.panel-success{border-color:#5eb95e}\n.panel-success > .panel-header{ border-color:#5eb95e; background-color:#5eb95e; color:#fff}\n\n/*警告面板*/\n.panel-warning{border-color:#f37b1d}\n.panel-warning > .panel-header{ border-color:#f37b1d; background-color:#f37b1d; color:#fff}\n\n/*危险面板*/\n.panel-danger{border-color:#dd514c}\n.panel-danger > .panel-header{ border-color:#dd514c; background-color:#dd514c; color:#fff}\n\n/*4.15 案例\n\tName:\t\t\tmod_docs-example\n\tExample:\t\t<div class=\"docs-example tooltip-demo\">……</div>\n*/\n.docs-example{position:relative;*position:static;*padding-top: 19px;margin: 15px 0;padding: 39px 19px 14px;background-color: #fff;border: 1px solid #ddd;border-radius: 4px}\n.docs-example:after{content: \"Example\";position: absolute;top: -1px;left: -1px;*position:static;padding: 3px 7px;font-size: 12px;font-weight: bold;background-color: #f5f5f5;border: 1px solid #ddd;color: #9da0a4;border-radius: 4px 0 4px 0}\n\n/*4.16 滚动\n\tName:\t\t\tmod_rolling\n\tExample:\t\t<div class=\"rollpicshow\"><ul><li>……</li></ul></div>\n*/\n.marquee{height:22px;overflow:hidden;line-height:22px}\n.rollpic .prev,.rollpic .next{display:block; height:38px; width:38px; cursor:pointer; float:left; background:url(../images/rollpic/unslider-arrow.png) no-repeat 0 0; margin-top:70px}\n.rollpic .prev{background-position:0 0; margin-right:5px}\n.rollpic .prev:hover{background-position:0 -38px}\n.rollpic .next{background-position:0 -76px;margin-left:5px}\n.rollpic .next:hover{background-position:0 -114px}\n.rollpicshow{float:left; border:solid 1px #ddd}\n.rollpicshow li{padding:10px}\n\n/*4.17 搜索条\n\tName:\t\t\tmod_searchBar\n\tSample:\n<div class=\"searchBar\">\n  <form class=\"form-search\" method=\"post\" action=\"\">\n    <input id=\"searchKeyword\" name=\"searchKeyword\" value=\"请输入搜索关键词\" class=\"input-text searchTxt\">\n    <input id=\"searchBtn\" name=\"searchBtn\" type=\"submit\" value=\"搜索\" class=\"btn btn-default searchBtn\" onclick=\"b_onclick()\">\n  </form>\n</div>\n*/\n\t/*搜索下拉提示*/\n.ac_results{position:absolute;border:solid 1px #ddd;background-color:#fff; padding:3px; display:none; margin-top:-1px; z-index:999}\n.ac_results ul{width:100%;list-style-position:outside;list-style:none;padding:0;margin:0}\n.ac_results li{padding-left:5px;padding-right:5px;display:block;height:24px;line-height:24px;cursor:pointer}\n.ac_results li p{ float:left;margin:0;padding:0;overflow:hidden}\n.ac_results li p tt{color:#666}\n.ac_results li span{margin:0;padding:0;display:inline;float:right;color:#f93;width:90px; text-align:right; overflow:hidden}\n.ac_results li.ac_even{}\n.ac_results li.ac_odd{}\n.ac_results li.ac_over{background-color:#f0f1f2}\n\t.ac_loading{background:#fff url(../images/loading/loading-s.gif) right center no-repeat}\n\n/*4.18.1 对联广告\n\tName:\t\t\tmod_AD_dual\n\tSample:\n\t<div class=\"dual dual_l\"><div class=\"dual_con\">对联的内容</div><a href=\"#\" class=\"dual_close\">X关闭</a></div>\n\t<div class=\"dual dual_r\"><div class=\"dual_con\">对联的内容</div><a href=\"#\" class=\"dual_close\">X关闭</a></div>\n*/\n.AD{text-align:center}\n.dual{top:260px;position:absolute; width:102px; overflow:hidden; display:none; z-index:100}\n.dual_l{left:6px}\n.dual_r{right:6px}\n.dual_con{border:#CCC solid 1px;width:100px; height:300px; overflow:hidden; background-color:#0C9}\n.dual_close{width:100%;height:24px; line-height:24px; text-align:center; display:block; font-size:13px; color:#555; text-decoration:none}\n\n/*4.19 标签*/\n\t/*4.19.1 标签输入效果\n\t\tName:\t\t\tmod_Hui-tags\n\t\tSample:\n\t\t<div class=\"Hui-tags\">\n\t\t  <div class=\"Hui-tags-editor cl\"><i class=\"Hui-tags-icon\"></i>\n\t\t\t<span class=\"Hui-tags-token\">Hui前端框架</span>\n\t\t\t<span class=\"Hui-tags-token\">CSS3</span>\n\t\t\t<span class=\"Hui-tags-token\">HTML5</span>\n\t\t\t<div class=\"Hui-tags-iptwrap\"><input type=\"text\" class=\"Hui-tags-input\" maxlength=\"20\" value=\"\"><label class=\"Hui-tags-label\">添加相关标签，用空格或回车分隔</label></div>\n\t\t  </div>\n\t\t  <div class=\"Hui-tags-list\">\n\t\t\t<div class=\"Hui-notag\">暂无常用标签</div>\n\t\t\t<div class=\"Hui-tags-has\"><span>前端框架</span> <span>前端开发</span> <span>H-ui</span></div>\n\t\t  </div>\n\t\t  <input type=\"hidden\" class=\"Hui-tags-val\" name=\"\" value=\"\">\n\t\t</div>\n\t*/\n\t.Hui-tags,\n\t.Huitags-wraper{border:solid 1px #dedede; padding:0 10px}\n\t\t.Hui-tags-editor,\n\t\t.Huitags-editor{position:relative; padding:10px 0 10px 24px;min-height:20px}\n\t\t\n\t\t.Hui-tags-editor .Hui-tags-icon,\n\t\t.Huitags-editor .Huitags-icon{position:absolute; left:0; top:11px; font-size:14px; color:#666}\n\t\t\n\t\t\t.Hui-tags-token,\n\t\t\t.Huitags-token{color:#aaa; float:left; font-size:12px; height:20px; line-height:20px; margin-right:8px; padding:0 1px; white-space:nowrap; cursor:pointer}\n\t\t\t.Hui-tags-token:before,\n\t\t\t.Huitags-token:before{content:\"#\"}\n\t\t\t.Hui-tags-token:hover,\n\t\t\t.Huitags-token:hover{text-decoration:line-through}\n\t\t\t\n\t\t\t.Hui-tags-iptwrap{position:relative; float:left}\n\t\t\t.Huitags-input-wraper{}\n\t\t\t\t.Hui-tags-input\n\t\t\t\t{position:relative;height:20px;min-width:60px; border:0 none; vertical-align:top;line-height:20px; color:#333;z-index:2;background: url(../images/Hui-tags/empty.png) repeat scroll 0 0; display:inline-block; width:100%}\n\t\t\t\t.Huitags-input{}\n\t\t\t\t.Hui-tags-label,\n\t\t\t\t.Huitags-label{position:absolute; top:0; left:2px; width:240px; height:20px; line-height:20px; font-size:14px; overflow:hidden; z-index:1; color:#ccc}\n\t\t\t\t\n\t\t\t.Hui-tags-list,\n\t\t\t.Huitags-list{padding:0 0 10px 0;}\n\t\t\t\n\t\t.Hui-notag,\n\t\t.Huitags-notag{font-size:12px}\n\t\t\n\t\t.Hui-tags-has span,\n\t\t.Huitags-has span{cursor:pointer; font-size:12px; white-space:nowrap; margin-right:10px}\n\t\n\t/*4.19.2 标签混排效果\n\t\tName:\t\t\tmod_tags\n\t\tSample:\t\t\t<div class=\"pd-10 tags\"><a href=\"http://www.h-ui.net/\">H-ui前端框架</a>……</div>\n\t\n\t*/\n\t.tags a{height:26px; line-height:26px;padding-right:6px}\n\t\t.tags0{}\n\t\t.tags1{color:#C00; font-size:24px}\n\t\t.tags2{color:#030; font-size:16px}\n\t\t.tags3{color:#00F}\n\t\t.tags4{font-size:16px}\n\t\t.tags5{color:#C00; font-size:20px}\n\t\t.tags6{color:#F06; font-size:20px}\n\t\t.tags7{color:#030; font-weight:bold; font-size:18px}\n\t\t.tags8{color:#F06; font-weight:bold}\n\t\t.tags9{color:#C00; font-weight:bold;font-size:16px}\n\t.tags a:hover{color:#F00; text-decoration:underline}\n\t\n\t/*4.19.3 tag云标签*/\n\t#tagyun {position:relative}\n\t#tagyun a {position:absolute;top:0px;left:0px;font-weight:bold;text-decoration:none;padding:3px 6px}\n\n/*4.20 折叠\n\tName:\t\t\tmod_Huifold\n\tSample:\n\t<ul id=\"\" class=\"Huifold\">\n\t  <li class=\"item\"><h4>标题<b>+</b></h4><div class=\"info\">内容 </div></li>\n\t  ……\n\t</ul>\n*/\n.Huifold .item{position:relative}\n.Huifold .item h4{margin:0;font-weight:bold;position:relative;border-top: 1px solid #fff;font-size:15px;line-height:22px;padding:7px 10px;background-color:#eee;cursor:pointer;padding-right:30px}\n.Huifold .item h4 b{position:absolute;display: block; cursor:pointer;right:10px;top:7px;width:16px;height:16px; text-align:center; color:#666}\n.Huifold .item .info{display:none;padding:10px}\n\n/*4.21 遮罩条\n\tName:\t\t\tmod_maskBar\n*/\n.maskBar{position:absolute;height:auto;left:0; bottom:-100%; right:0;padding:10px;background-color:rgba(0,0,0,0.6);z-index:2; color:#fff!important}\n.maskWraper{position:relative; overflow:hidden}\n.maskWraper.hover .maskBar{bottom:0px;\n\ttransition: bottom 200ms;\n\t-moz-transition: bottom 200ms; /* Firefox 4 */\n\t-webkit-transition: bottom 200ms; /* Safari 和 Chrome */\n\t-o-transition: bottom 200ms; /* Opera */\n}\n.maskBox{position:absolute;width:100%; height:100%;top:0;left:0; bottom:0;right:0;z-index:2;color:#fff!important}\n.maskWraper.hover .maskBox{background-color:rgba(0,0,0,0.6);\n\ttransition: all 500ms;\n\t-moz-transition: all 500ms; /* Firefox 4 */\n\t-webkit-transition: all 500ms; /* Safari 和 Chrome */\n\t-o-transition: all 500ms; /* Opera */\n}\n\n/*4.22 评论列表\n\tName:\t\t\tmod_comment\n\tSample:\n\t<ul class=\"commentList\">\n\t  <li class=\"item clearfix\">\n\t    <a href=\"#\"><i class=\"avatar avatar-L radius\"><img alt=\"\" src=\"static/h-ui/images/ucenter/avatar-default.jpg\"></i></a>\n\t\t<div class=\"comment-main\">\n\t\t  <header class=\"comment-header\">\n\t\t    <div class=\"comment-meta\"><a class=\"comment-author\" href=\"#\">辉哥</a> 评论于 <time title=\"2014年8月31日 下午3:20\" datetime=\"2014-08-31T03:54:20\">2014-8-31 15:20</time></div>\n\t      </header>\n\t\t  <div class=\"comment-body\"><p><a href=\"#\">@某人</a> 你是猴子派来的救兵吗？</p></div></div>\n\t  </li>\n\t</ul>\n*/\n.commentList .item{list-style: none outside none;margin: 1.6rem 0 0}\n.commentList .avatar{border: 1px solid transparent;float: left}\n\t.comment-main{position:relative;margin-left:64px;border:1px solid #dedede;border-radius:2px}\n\t.comment-main:before,\n\t.comment-main:after{position:absolute;top:11px;left:-16px;right:100%;width:0;height:0;display:block;content:\" \";border-color:transparent;border-style:solid solid outset;pointer-events:none}\n\t.comment-main:before{border-right-color:#dedede;border-width:8px}\n\t.comment-main:after{border-width:7px;border-right-color:#f8f8f8;margin-top:1px;margin-left:2px}\n\t\t.comment-header{padding:10px 15px;background:#f8f8f8;border-bottom:1px solid #eee}\n\t\t.comment-title{margin:0 0 8px 0;font-size:1.6rem;line-height:1.2}\n\t\t.comment-meta{font-size:13px;color:#999;line-height:1.2}\n\t\t.comment-meta a{color:#999}\n\t\t.comment-author{font-weight:700;color:#999}\n\t\t.comment-body{padding:15px;overflow:hidden}\n\t\t.comment-body>:last-child{margin-bottom:0}\n.commentList .comment-flip .avatar {float: right}\n\t.comment-flip .comment-main{margin-left: 0; margin-right: 64px}\n\t.comment-flip .comment-main:before {border-left-color: #dedede;border-right-color: transparent}\n\t.comment-flip .comment-main:before,\n\t.comment-flip .comment-main:after {left: 100%;position: absolute;right: -16px}\n\t.comment-flip .comment-main:after {border-left-color: #f8f8f8;border-right-color: transparent;margin-left: auto;margin-right: 2px}\n\n/*4.23 页脚\n\tName:\t\t\tmod_footer\n\tSample:\n<footer class=\"footer mt-20\">\n  <div class=\"container\">\n    <nav class=\"footer-nav\">\n      <a target=\"_blank\" href=\"/aboutHui.html\">关于H-ui</a>\n      <span class=\"pipe\">|</span>\n      <a target=\"_blank\" href=\"/copyright.html\">软件著作权</a>\n      <span class=\"pipe\">|</span>\n      <a target=\"_blank\" href=\"/juanzeng.html\">感谢捐赠</a>\n    </nav>\n    <p>Copyright &copy;2013-2016 H-ui.net All Rights Reserved. <br>\n    <a rel=\"nofollow\" target=\"_blank\" href=\"http://www.miitbeian.gov.cn/\">京ICP备10000000号</a><br>\n    未经允许，禁止转载、抄袭、镜像</p>\n  </div>\n</footer>\n*/\n.footer{border-top:1px solid #E8E8E8; padding:15px 0;font-family:tahoma,Arial;font-size:12px;color:#999;line-height:22px;text-align:center}\n.footer a,.footer a:hover{color:#999}\n\n/*4.24 星星评价\n\tName:\t\t\tmod_star\n\tSample:\n显示分数效果 可以是百分比\n<div class=\"star-bar star-bar-show size-M\">\n\t<span class=\"star\" style=\"width:75%\"></span>\n</div>\n\n打分效果 结构是js生成。\n<div id=\"\" class=\"star-bar size-M \"></div>\n*/\n.star-bar-show{background:url(../images/star/iconpic-star-S-default.png) repeat-x 0 0}\n.star-bar-show .star{background:url(../images/star/iconpic-star-S.png) repeat-x 0 0}\n.star-1{width:20%}\n.star-2{ width:40%}\n.star-3{width:60%}\n.star-4{ width:80%}\n.star-5{ width:100%}\n.star-bar-show.size-M{width:120px;height:24px}\n.star-bar-show.size-M,.star-bar-show.size-M .star{background-size:24px}\n.star-bar-show.size-M .star{ height:24px}\n.star-bar-show.size-S{width:80px; height:16px}\n.star-bar-show.size-S,.star-bar-show.size-S .star{background-size:16px}\n.star-bar-show.size-S .star{ height:16px}\n\n.star-bar{font-size:0; line-height:0}\n.star-bar .star{display:inline-block;text-align:center}\n/*中*/\n.size-M img{ width:24px;height:24px}\n/*小*/\n.size-S img{width:16px;height:16px}\n\n/*4.25 tooltip 效果\n\tName:\t\t\tmod_tooltip\n*/\n.tooltip {position: absolute;z-index: 1070;display: block;font-size: 12px;line-height: 1.4;visibility: visible;filter: alpha(opacity=0);opacity: 0}\n.tooltip.in {filter: alpha(opacity=90);opacity: .9}\n.tooltip.top {padding: 5px 0;margin-top: -3px}\n.tooltip.right {padding: 0 5px;margin-left: 3px}\n.tooltip.bottom {padding: 5px 0;margin-top: 3px}\n.tooltip.left {padding: 0 5px;margin-left: -3px}\n\t.tooltip-inner {max-width: 200px;padding: 3px 8px;color: #fff;text-align: center;text-decoration: none;background-color: #000;border-radius: 4px}\n\t.tooltip-arrow {position: absolute;width: 0;height: 0;border-color: transparent;border-style: solid}\n.tooltip.top .tooltip-arrow {bottom: 0;left: 50%;margin-left: -5px;border-width: 5px 5px 0;border-top-color: #000}\n.tooltip.top-left .tooltip-arrow {bottom: 0;left: 5px;border-width: 5px 5px 0;border-top-color: #000}\n.tooltip.top-right .tooltip-arrow {right: 5px;bottom: 0;border-width: 5px 5px 0;border-top-color: #000}\n.tooltip.right .tooltip-arrow {top: 50%;left: 0;margin-top: -5px;border-width: 5px 5px 5px 0;border-right-color: #000}\n.tooltip.left .tooltip-arrow {top: 50%;right: 0;margin-top: -5px;border-width: 5px 0 5px 5px;border-left-color: #000}\n.tooltip.bottom .tooltip-arrow {top: 0;left: 50%;margin-left: -5px;border-width: 0 5px 5px;border-bottom-color: #000}\n.tooltip.bottom-left .tooltip-arrow {top: 0;left: 5px;border-width: 0 5px 5px;border-bottom-color: #000}\n.tooltip.bottom-right .tooltip-arrow {top: 0;right: 5px;border-width: 0 5px 5px;border-bottom-color: #000}\n\n/*4.26 popover 效果\n\tName:\t\t\tmod_popover\n*/\n.popover {position: absolute;top: 0;left: 0;z-index: 1060;display: none;max-width: 276px;padding: 1px;font-size: 14px;font-weight: normal;line-height: 1.42857143;text-align: left;white-space: normal;background-color: #fff;-webkit-background-clip: padding-box;background-clip: padding-box;border: 1px solid #ccc;border: 1px solid rgba(0, 0, 0, .2);border-radius: 6px;-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);box-shadow: 0 5px 10px rgba(0, 0, 0, .2)}\n.popover.top {margin-top: -10px}\n.popover.right {margin-left: 10px}\n.popover.bottom {margin-top: 10px}\n.popover.left {margin-left: -10px}\n.popover-title {padding: 8px 14px;margin: 0;font-size: 14px;background-color: #f7f7f7;border-bottom: 1px solid #ebebeb;border-radius: 5px 5px 0 0}\n.popover-content {padding: 9px 14px}\n.popover > .arrow,.popover > .arrow:after {position: absolute;display: block;width: 0;height: 0;border-color: transparent;border-style: solid}\n.popover > .arrow {border-width: 11px}\n.popover > .arrow:after {content: \"\";border-width: 10px}\n.popover.top > .arrow {bottom: -11px;left: 50%;margin-left: -11px;border-top-color: #999;border-top-color: rgba(0, 0, 0, .25);border-bottom-width: 0}\n.popover.top > .arrow:after {bottom: 1px;margin-left: -10px;content: \" \";border-top-color: #fff;border-bottom-width: 0}\n.popover.right > .arrow {top: 50%;left: -11px;margin-top: -11px;border-right-color: #999;border-right-color: rgba(0, 0, 0, .25);border-left-width: 0}\n.popover.right > .arrow:after {bottom: -10px;left: 1px;content: \" \";border-right-color: #fff;border-left-width: 0}\n.popover.bottom > .arrow {top: -11px;left: 50%;margin-left: -11px;border-top-width: 0;border-bottom-color: #999;border-bottom-color: rgba(0, 0, 0, .25)}\n.popover.bottom > .arrow:after {top: 1px;margin-left: -10px;content: \" \";border-top-width: 0;border-bottom-color: #fff}\n.popover.left > .arrow {top: 50%;right: -11px;margin-top: -11px;border-right-width: 0;border-left-color: #999;border-left-color: rgba(0, 0, 0, .25)}\n.popover.left > .arrow:after {right: 1px;bottom: -10px;content: \" \";border-right-width: 0;border-left-color: #fff}\n\n/*4.27 datetimepicker日期插件\n\tName:\t\t\tmod_datetimepicker\n\tSample:\n*/\n.datetimepicker {padding: 4px;margin-top: 1px;-webkit-border-radius: 4px;-moz-border-radius: 4px;border-radius: 4px;direction: ltr;position: absolute;top: 100%;left: 0;z-index: 1000;display: none;float: left;min-width: 160px;padding: 5px 0;margin: 2px 0 0;font-size: 14px;list-style: none;background-color: #ffffff;border: 1px solid #cccccc;border: 1px solid rgba(0, 0, 0, 0.15);border-radius: 4px;-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);background-clip: padding-box}\n.datetimepicker-inline {width: 220px}\n.datetimepicker.datetimepicker-rtl {direction: rtl}\n.datetimepicker.datetimepicker-rtl table tr td span {float: right}\n.datetimepicker-dropdown, .datetimepicker-dropdown-left {top: 0;left: 0}\n[class*=\" datetimepicker-dropdown\"]:before {content: '';display: inline-block;border-left: 7px solid transparent;border-right: 7px solid transparent;border-bottom: 7px solid #cccccc;border-bottom-color: rgba(0, 0, 0, 0.2);position: absolute}\n[class*=\" datetimepicker-dropdown\"]:after {content: '';display: inline-block;border-left: 6px solid transparent;border-right: 6px solid transparent;border-bottom: 6px solid #fff;position: absolute}\n[class*=\" datetimepicker-dropdown-top\"]:before {content: '';display: inline-block;border-left: 7px solid transparent;border-right: 7px solid transparent;border-top: 7px solid #ccc;border-top-color: rgba(0, 0, 0, 0.2);border-bottom: 0}\n[class*=\" datetimepicker-dropdown-top\"]:after {content: '';display: inline-block;border-left: 6px solid transparent;border-right: 6px solid transparent;border-top: 6px solid #fff;border-bottom: 0}\n.datetimepicker-dropdown-bottom-left:before {top: -7px;right: 6px}\n.datetimepicker-dropdown-bottom-left:after {top: -6px;right: 7px}\n.datetimepicker-dropdown-bottom-right:before {top: -7px;left: 6px}\n.datetimepicker-dropdown-bottom-right:after {top: -6px;left: 7px}\n.datetimepicker-dropdown-top-left:before {bottom: -7px;right: 6px}\n.datetimepicker-dropdown-top-left:after {bottom: -6px;right: 7px}\n.datetimepicker-dropdown-top-right:before {bottom: -7px;left: 6px}\n.datetimepicker-dropdown-top-right:after {bottom: -6px;left: 7px}\n.datetimepicker > div {display: none}\n.datetimepicker.minutes div.datetimepicker-minutes {display: block}\n.datetimepicker.hours div.datetimepicker-hours {display: block}\n.datetimepicker.days div.datetimepicker-days {display: block}\n.datetimepicker.months div.datetimepicker-months {display: block}\n.datetimepicker.years div.datetimepicker-years {display: block}\n.datetimepicker table {margin: 0}\n.datetimepicker  td,\n.datetimepicker th {text-align: center;width: 20px;height: 20px;-webkit-border-radius: 4px;-moz-border-radius: 4px;border-radius: 4px;border: none}\n.table-striped .datetimepicker table tr td,\n.table-striped .datetimepicker table tr th {background-color: transparent}\n.datetimepicker table tr td.minute:hover {background: #eee;cursor: pointer}\n.datetimepicker table tr td.hour:hover {background: #eee;cursor: pointer}\n.datetimepicker table tr td.day:hover {background: #eee;cursor: pointer}\n.datetimepicker table tr td.old,\n.datetimepicker table tr td.new {color: #999}\n.datetimepicker table tr td.disabled,\n.datetimepicker table tr td.disabled:hover {background: none;color: #999;cursor: default}\n\n.datetimepicker table tr td.today,\n.datetimepicker table tr td.today:hover,\n.datetimepicker table tr td.today.disabled,\n.datetimepicker table tr td.today.disabled:hover {background-color: #fde19a;background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);\n\tbackground-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);\n\tbackground-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));\n\tbackground-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);\n\tbackground-image: -o-linear-gradient(top, #fdd49a, #fdf59a);\n\tbackground-image: linear-gradient(top, #fdd49a, #fdf59a);\n\tbackground-repeat: repeat-x;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);border-color: #fdf59a #fdf59a #fbed50;border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter: progid:DXImageTransform.Microsoft.gradient(enabled=false)}\n\n.datetimepicker table tr td.today:hover,\n.datetimepicker table tr td.today:hover:hover,\n.datetimepicker table tr td.today.disabled:hover,\n.datetimepicker table tr td.today.disabled:hover:hover,\n.datetimepicker table tr td.today:active,\n.datetimepicker table tr td.today:hover:active,\n.datetimepicker table tr td.today.disabled:active,\n.datetimepicker table tr td.today.disabled:hover:active,\n.datetimepicker table tr td.today.active,\n.datetimepicker table tr td.today:hover.active,\n.datetimepicker table tr td.today.disabled.active,\n.datetimepicker table tr td.today.disabled:hover.active,\n.datetimepicker table tr td.today.disabled,\n.datetimepicker table tr td.today:hover.disabled,\n.datetimepicker table tr td.today.disabled.disabled,\n.datetimepicker table tr td.today.disabled:hover.disabled,\n.datetimepicker table tr td.today[disabled],\n.datetimepicker table tr td.today:hover[disabled],\n.datetimepicker table tr td.today.disabled[disabled],\n.datetimepicker table tr td.today.disabled:hover[disabled] {background-color: #fdf59a}\n.datetimepicker table tr td.today:active,\n.datetimepicker table tr td.today:hover:active,\n.datetimepicker table tr td.today.disabled:active,\n.datetimepicker table tr td.today.disabled:hover:active,\n.datetimepicker table tr td.today.active,\n.datetimepicker table tr td.today:hover.active,\n.datetimepicker table tr td.today.disabled.active,\n.datetimepicker table tr td.today.disabled:hover.active {background-color: #fbf069}\n.datetimepicker table tr td.active,\n.datetimepicker table tr td.active:hover,\n.datetimepicker table tr td.active.disabled,\n.datetimepicker table tr td.active.disabled:hover {background-color: #006dcc;\n\tbackground-image: -moz-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -ms-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));\n\tbackground-image: -webkit-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -o-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: linear-gradient(top, #0088cc, #0044cc);\n\tbackground-repeat: repeat-x;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);border-color: #0044cc #0044cc #002a80;border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);color: #fff;text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25)}\n\n.datetimepicker table tr td.active:hover,\n.datetimepicker table tr td.active:hover:hover,\n.datetimepicker table tr td.active.disabled:hover,\n.datetimepicker table tr td.active.disabled:hover:hover,\n.datetimepicker table tr td.active:active,\n.datetimepicker table tr td.active:hover:active,\n.datetimepicker table tr td.active.disabled:active,\n.datetimepicker table tr td.active.disabled:hover:active,\n.datetimepicker table tr td.active.active,\n.datetimepicker table tr td.active:hover.active,\n.datetimepicker table tr td.active.disabled.active,\n.datetimepicker table tr td.active.disabled:hover.active,\n.datetimepicker table tr td.active.disabled,\n.datetimepicker table tr td.active:hover.disabled,\n.datetimepicker table tr td.active.disabled.disabled,\n.datetimepicker table tr td.active.disabled:hover.disabled,\n.datetimepicker table tr td.active[disabled],\n.datetimepicker table tr td.active:hover[disabled],\n.datetimepicker table tr td.active.disabled[disabled],\n.datetimepicker table tr td.active.disabled:hover[disabled] {background-color: #04c}\n\n.datetimepicker table tr td.active:active,\n.datetimepicker table tr td.active:hover:active,\n.datetimepicker table tr td.active.disabled:active,\n.datetimepicker table tr td.active.disabled:hover:active,\n.datetimepicker table tr td.active.active,\n.datetimepicker table tr td.active:hover.active,\n.datetimepicker table tr td.active.disabled.active,\n.datetimepicker table tr td.active.disabled:hover.active {background-color: #039}\n\n.datetimepicker table tr td span {display: block;width: 23%;height: 54px;line-height: 54px;float: left;margin: 1%;\tcursor: pointer;-webkit-border-radius: 4px;-moz-border-radius: 4px;border-radius: 4px}\n\n.datetimepicker .datetimepicker-hours span {height: 26px;line-height: 26px}\n\n.datetimepicker .datetimepicker-hours table tr td span.hour_am,\n.datetimepicker .datetimepicker-hours table tr td span.hour_pm {width: 14.6%}\n\n.datetimepicker .datetimepicker-hours fieldset legend,\n.datetimepicker .datetimepicker-minutes fieldset legend {margin-bottom: inherit;line-height: 30px}\n.datetimepicker .datetimepicker-minutes span {height: 26px;line-height: 26px}\n.datetimepicker table tr td span:hover {background: #eee}\n\n.datetimepicker table tr td span.disabled,\n.datetimepicker table tr td span.disabled:hover {background: none;color: #999;cursor: default}\n.datetimepicker table tr td span.active,\n.datetimepicker table tr td span.active:hover,\n.datetimepicker table tr td span.active.disabled,\n.datetimepicker table tr td span.active.disabled:hover {background-color: #006dcc;\n\tbackground-image: -moz-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -ms-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));\n\tbackground-image: -webkit-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: -o-linear-gradient(top, #0088cc, #0044cc);\n\tbackground-image: linear-gradient(top, #0088cc, #0044cc);\n\tbackground-repeat: repeat-x;\n\tfilter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);border-color: #0044cc #0044cc #002a80;border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);color: #fff;text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25)}\n\n.datetimepicker table tr td span.active:hover,\n.datetimepicker table tr td span.active:hover:hover,\n.datetimepicker table tr td span.active.disabled:hover,\n.datetimepicker table tr td span.active.disabled:hover:hover,\n.datetimepicker table tr td span.active:active,\n.datetimepicker table tr td span.active:hover:active,\n.datetimepicker table tr td span.active.disabled:active,\n.datetimepicker table tr td span.active.disabled:hover:active,\n.datetimepicker table tr td span.active.active,\n.datetimepicker table tr td span.active:hover.active,\n.datetimepicker table tr td span.active.disabled.active,\n.datetimepicker table tr td span.active.disabled:hover.active,\n.datetimepicker table tr td span.active.disabled,\n.datetimepicker table tr td span.active:hover.disabled,\n.datetimepicker table tr td span.active.disabled.disabled,\n.datetimepicker table tr td span.active.disabled:hover.disabled,\n.datetimepicker table tr td span.active[disabled],\n.datetimepicker table tr td span.active:hover[disabled],\n.datetimepicker table tr td span.active.disabled[disabled],\n.datetimepicker table tr td span.active.disabled:hover[disabled] {background-color: #0044cc}\n\n.datetimepicker table tr td span.active:active,\n.datetimepicker table tr td span.active:hover:active,\n.datetimepicker table tr td span.active.disabled:active,\n.datetimepicker table tr td span.active.disabled:hover:active,\n.datetimepicker table tr td span.active.active,\n.datetimepicker table tr td span.active:hover.active,\n.datetimepicker table tr td span.active.disabled.active,\n.datetimepicker table tr td span.active.disabled:hover.active {background-color: #039}\n.datetimepicker table tr td span.old {color: #999}\n.datetimepicker th.switch {width: 145px}\n.datetimepicker th span.glyphicon {pointer-events: none}\n.datetimepicker thead tr:first-child th,\n.datetimepicker tfoot th {cursor: pointer}\n.datetimepicker thead tr:first-child th:hover,\n.datetimepicker tfoot th:hover {background: #eee}\n.input-append.date .add-on i,\n.input-prepend.date .add-on i,\n.input-group.date .input-group-addon span {cursor: pointer;width: 14px;height: 14px}\n\n/*4.27 分类检索\n\tName:\t\t\tmod_select-category\n\tSample:\n<div class=\"select-category\">\n\t<div class=\"item clearfix\">\n\t\t<dl>\n\t\t\t<dt class=\"dt\">选择区域：</dt>\n\t\t\t<dd class=\"dd\">\n\t\t\t\t<a href=\"#\" title=\"北京市\">北京市</a>  \n            </dd>\n\t\t</dl>\n\t</div>\n</div>\n*/\n.select-category{}\n.select-category .item{padding:5px; position:relative; border-bottom:solid 1px #ddd}\n.select-category .item .dt{ width:90px; float:left;white-space:nowrap}\n.select-category .item .dd{ margin-left:100px; text-align:left; font-size:14px; height:auto}\n.select-category .item .dd a{ display:inline-block;white-space:nowrap; overflow:hidden;text-overflow:ellipsis; margin-right:10px; padding:0 5px; text-decoration:none}\n\n/*4.28 sortable拖动*/\n.ui-state-highlight{ height:50px; margin-top:20px;border:1px solid #fcefa1;background:#fbf9ee;color:#363636}\n.sortable-control{ cursor:move}\n\n/*4.29 ColorPicker 颜色控件*/\n\n\n/*5 页面\n\tName:\t\t\tpage\n*/\n\n/*5.1 错误页-404*/\n.page-404{ color:#afb5bf; padding-top:60px; padding-bottom:90px}\n.page-404 .error-title{font-size:80px}\n.page-404 .error-title .iconfont{font-size:80px}\n.page-404 .error-description{font-size:24px}\n.page-404 .error-info{font-size:14px}\n\n/*5.2 博客列表页*/\n.page-blog-list{}\n/*5.3 博客详情页*/\n.page-blog-show{}\n/*5.4 关于我们页*/\n.page-about-show{}\n/*5.5 帮助列表页*/\n.page-help-list{}\n/*5.6 帮助详情页*/\n.page-help-show{}\n/*5.7 友情链接页*/\n.page-flink{}\n"
  },
  {
    "path": "public/static/h-ui/css/H-ui.ie.css",
    "content": "/* -----------H-ui前端框架-------------\n* H-ui.ie.css v1.0\n* http://www.h-ui.net/\n* Created & Modified by guojunhui\n* Date modified 2016.05.02\n*\n* Copyright 2013-2016 北京颖杰联创科技有限公司 All rights reserved.\n* Licensed under MIT license.\n* http://opensource.org/licenses/MIT\n*\n*/\n@charset \"utf-8\";\n.navbar-fixed-top{ border-bottom:solid 1px #eee}\n.col-1,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-10,.col-11,.col-12,.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{ float:left}\n.col-md-12{width:100%}\n.col-md-11{width:91.66666666666666%}\n.col-md-10{width:83.33333333333334%}\n.col-md-9{width:75%}\n.col-md-8{width:66.66666666666666%}\n.col-md-7{width:58.333333333333336%}\n.col-md-6{width:50%}\n.col-md-5{width:41.66666666666667%}\n.col-md-4{width:33.33333333333333%}\n.col-md-3{width:25%}\n.col-md-2{width:16.666666666666664%}\n.col-md-1{width:8.333333333333332%}\n.col-md-pull-12{right:100%}\n.col-md-pull-11{right:91.66666666666666%}\n.col-md-pull-10{right:83.33333333333334%}\n.col-md-pull-9{right:75%}\n.col-md-pull-8{right:66.66666666666666%}\n.col-md-pull-7{right:58.333333333333336%}\n.col-md-pull-6{right:50%}\n.col-md-pull-5{right:41.66666666666667%}\n.col-md-pull-4{right:33.33333333333333%}\n.col-md-pull-3{right:25%}\n.col-md-pull-2{right:16.666666666666664%}\n.col-md-pull-1{right:8.333333333333332%}\n.col-md-pull-0{right:0}\n.col-md-push-12{left:100%}\n.col-md-push-11{left:91.66666666666666%}\n.col-md-push-10{left:83.33333333333334%}\n.col-md-push-9{left:75%}\n.col-md-push-8{left:66.66666666666666%}\n.col-md-push-7{left:58.333333333333336%}\n.col-md-push-6{left:50%}\n.col-md-push-5{left:41.66666666666667%}\n.col-md-push-4{left:33.33333333333333%}\n.col-md-push-3{left:25%}\n.col-md-push-2{left:16.666666666666664%}\n.col-md-push-1{left:8.333333333333332%}\n.col-md-push-0{left:0}\n.col-md-offset-12{margin-left:100%}\n.col-md-offset-11{margin-left:91.66666666666666%}\n.col-md-offset-10{margin-left:83.33333333333334%}\n.col-md-offset-9{margin-left:75%}\n.col-md-offset-8{margin-left:66.66666666666666%}\n.col-md-offset-7{margin-left:58.333333333333336%}\n.col-md-offset-6{margin-left:50%}\n.col-md-offset-5{margin-left:41.66666666666667%}\n.col-md-offset-4{margin-left:33.33333333333333%}\n.col-md-offset-3{margin-left:25%}\n.col-md-offset-2{margin-left:16.666666666666664%}\n.col-md-offset-1{margin-left:8.333333333333332%}\n.col-md-offset-0{margin-left:0}\n\n"
  },
  {
    "path": "public/static/h-ui/css/H-ui.reset.css",
    "content": "﻿@charset \"utf-8\";\n/* -----------H-ui前端框架-------------\n* H-ui.reset.css v1.2\t重定义浏览器默认样式\n* http://www.h-ui.net/\n* Created & Modified by guojunhui\n* Date modified 2014.10.09\n*\n* Copyright 2013-2015 北京颖杰联创科技有限公司 All rights reserved.\n* Licensed under MIT license.\n* http://opensource.org/licenses/MIT\n*\n*/\n/*1 重定义浏览器默认样式\n\tName:\t\t\tstyle_reset\n\tLevel:\t\t\tGlobal\n\tExplain:\t\t重定义浏览器默认样式\n\tLast Modify:\tjackying\n*/\n*{word-wrap:break-word}\nhtml,body,h1,h2,h3,h4,h5,h6,hr,p,iframe,dl,dt,dd,ul,ol,li,pre,form,button,input,textarea,th,td,fieldset{margin:0;padding:0}\nul,ol,dl{list-style-type:none}\nhtml,body{*position:static}\nhtml{font-family: sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}\naddress,caption,cite,code,dfn,em,th,var{font-style:normal;font-weight:400}\ninput,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit}\ninput,button{overflow: visible;vertical-align:middle;outline:none}\nbody,th,td,button,input,select,textarea{font-family:\"Microsoft Yahei\",\"Hiragino Sans GB\",\"Helvetica Neue\",Helvetica,tahoma,arial,Verdana,sans-serif,\"WenQuanYi Micro Hei\",\"\\5B8B\\4F53\";font-size:12px;color: #333;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing:grayscale}\nbody{line-height:1.6}\nh1,h2,h3,h4,h5,h6{font-size:100%}\na,area{outline:none;blr:expression(this.onFocus=this.blur())}\na{text-decoration:none;cursor: pointer}\na:hover{text-decoration:underline;outline:none}\na.ie6:hover{zoom:1}\na:focus{outline:none}\na:hover,a:active{outline:none}:focus{outline:none}\nsub,sup{vertical-align:baseline}\nbutton,input[type=\"button\"], input[type=\"submit\"] {line-height:normal !important;}\n/*img*/\nimg{border:0;vertical-align:middle}\na img,img{-ms-interpolation-mode:bicubic}\n.img-responsive{max-width: 100%;height: auto}\n\n/*IE下a:hover 背景闪烁*/\n*html{overflow:-moz-scrollbars-vertical;zoom:expression(function(ele){ele.style.zoom = \"1\";document.execCommand(\"BackgroundImageCache\",false,true)}(this))}\n\n/*HTML5 reset*/\nheader,footer,section,aside,details,menu,article,section,nav,address,hgroup,figure,figcaption,legend{display:block;margin:0;padding:0}time{display:inline}\naudio,canvas,video{display:inline-block;*display:inline;*zoom:1}\naudio:not([controls]){display:none}\nlegend{width:100%;margin-bottom:20px;font-size:21px;line-height:40px;border:0;border-bottom:1px solid #e5e5e5}\nlegend small{font-size:15px;color:#999}\nsvg:not(:root) {overflow: hidden}\nfieldset {border-width:0;padding: 0.35em 0.625em 0.75em;margin: 0 2px;border: 1px solid #c0c0c0}\ninput[type=\"number\"]::-webkit-inner-spin-button,input[type=\"number\"]::-webkit-outer-spin-button {height: auto}\ninput[type=\"search\"] {-webkit-appearance: textfield; /* 1 */-moz-box-sizing: content-box;-webkit-box-sizing: content-box; /* 2 */box-sizing: content-box}\ninput[type=\"search\"]::-webkit-search-cancel-button,input[type=\"search\"]::-webkit-search-decoration {-webkit-appearance: none}\n/*\n\tName:\t\t\tstyle_clearfix\n\tExample:\t\tclass=\"clearfix|cl\"\n\tExplain:\t\tClearfix（简写cl）避免因子元素浮动而导致的父元素高度缺失能问题\n*/\n.cl:after,.clearfix:after{content:\".\";display:block;height:0;clear:both;visibility:hidden}.cl,.clearfix{zoom:1}"
  },
  {
    "path": "public/static/h-ui/js/H-ui.js",
    "content": "/*-----------H-ui前端框架-------------\n* H-ui.js v3.1.3\n* http://www.h-ui.net/\n* Created & Modified by guojunhui\n* Date modified 2017.05.26\n*\n* Copyright 2013-2017 北京颖杰联创科技有限公司 All rights reserved.\n* Licensed under MIT license.\n* http://opensource.org/licenses/MIT\n*/\n/*\nIncludes：\njQuery.IEMobileHack.js\njQuery.cookie.js v1.4.1\njQuery.form.js v3.51.0\njQuery.lazyload.js v1.9.3\njQuery.responsive-nav.js v1.0.39\njQuery.placeholder.js\njQuery.emailsuggest.js v1.0\njQuery.format.js\njQuery.togglePassword.js\njQuery.iCheck.js\njQuery.raty.js v2.4.5\njQuery.onePageNav.js\njQuery.stickUp.js\njQuery.ColorPicker.js\n\njQuery.HuiaddFavorite.js\njQuery.Huisethome.js\njQuery.Huisidenav.js\njQuery.Huihover.js v2.0\njQuery.Huifocusblur.js V2.0\njQuery.Huiselect.js\njQuery.Huitab.js v2.0\njQuery.Huifold.js v2.0\njQuery.Huitags.js v2.0\njQuery.Huitagsmixed.js\njQuery.Huitextarealength.js v2.0\njQuery.Huipreview.js v2.0\njQuery.Huimodalalert.js\njQuery.Huialert.js\njQuery.Huitotop.js v2.0\njQuery.Huimarquee.js\njQuery.Huispinner.js v2.0\n\nBootstrap.modal.js v3.3.0\nBootstrap.dropdown.js v3.3.0\nBootstrap.transition.js v3.3.0\nBootstrap.tooltip.js v3.3.0\nBootstrap.popover.js v3.3.0\nBootstrap.alert.js v3.3.0\nBootstrap.slider.js v1.0.1\nBootstrap.datetimepicker.js\nBootstrap.Switch v1.3\n\n*/\n/* =======================================================================\n * jQuery.IEMobileHack.js判断浏览器\n * ======================================================================== */\n!function(){\n\tif (navigator.userAgent.match(/IEMobile\\/10\\.0/)) {\n\t\tvar msViewportStyle = document.createElement(\"style\");\n\t\tmsViewportStyle.appendChild(\n\t\t\tdocument.createTextNode(\n\t\t\t\t\"@-ms-viewport{width:auto!important}\"\n\t\t\t)\n\t\t);\n\t\tdocument.getElementsByTagName(\"head\")[0].appendChild(msViewportStyle);\n\t}\n} ();\n\n/* =======================================================================\n * jQuery.stopDefault.js 阻止默认浏览器动作\n * ======================================================================== */\nfunction stopDefault(e) {\n\tif (e && e.preventDefault) e.preventDefault();\n\t//IE中阻止函数器默认动作的方式\n\telse window.event.returnValue = false;\n\treturn false;\n}\n\n/* =======================================================================\n * jQuery.cookie.js v1.4.1\n * https://github.com/carhartl/jQuery-cookie\n *\n * Copyright 2006, 2014 Klaus Hartl\n * Released under the MIT license\n * ======================================================================== */\n!(function(factory) {\n\tif (typeof define === 'function' && define.amd) {\n\t\t// AMD (Register as an anonymous module)\n\t\tdefine(['jquery'], factory);\n\t} else if (typeof exports === 'object') {\n\t\t// Node/CommonJS\n\t\tmodule.exports = factory(require('jquery'));\n\t} else {\n\t\t// Browser globals\n\t\tfactory(jQuery);\n\t}\n}\n(function($){\n\tvar pluses = /\\+/g;\n\tfunction encode(s) {\n\t\treturn config.raw ? s : encodeURIComponent(s);\n\t}\n\tfunction decode(s) {\n\t\treturn config.raw ? s : decodeURIComponent(s);\n\t}\n\tfunction stringifyCookieValue(value) {\n\t\treturn encode(config.json ? JSON.stringify(value) : String(value));\n\t}\n\tfunction parseCookieValue(s) {\n\t\tif (s.indexOf('\"') === 0) {\n\t\t\t// This is a quoted cookie as according to RFC2068, unescape...\n\t\t\ts = s.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\');\n\t\t}\n\n\t\ttry {\n\t\t\t// Replace server-side written pluses with spaces.\n\t\t\t// If we can't decode the cookie, ignore it, it's unusable.\n\t\t\t// If we can't parse the cookie, ignore it, it's unusable.\n\t\t\ts = decodeURIComponent(s.replace(pluses, ' '));\n\t\t\treturn config.json ? JSON.parse(s) : s;\n\t\t} catch(e) {}\n\t}\n\tfunction read(s, converter) {\n\t\tvar value = config.raw ? s: parseCookieValue(s);\n\t\treturn $.isFunction(converter) ? converter(value) : value;\n\t}\n\tvar config = $.cookie = function(key, value, options) {\n\t\t// Write\n\t\tif (arguments.length > 1 && !$.isFunction(value)) {\n\t\t\toptions = $.extend({},\n\t\t\tconfig.defaults, options);\n\n\t\t\tif (typeof options.expires === 'number') {\n\t\t\t\tvar days = options.expires,\n\t\t\t\tt = options.expires = new Date();\n\t\t\t\tt.setMilliseconds(t.getMilliseconds() + days * 864e+5);\n\t\t\t}\n\n\t\t\treturn (document.cookie = [encode(key), '=', stringifyCookieValue(value), options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE\n\t\t\toptions.path ? '; path=' + options.path: '', options.domain ? '; domain=' + options.domain: '', options.secure ? '; secure': ''].join(''));\n\t\t}\n\t\t// Read\n\t\tvar result = key ? undefined: {},\n\t\t// To prevent the for loop in the first place assign an empty array\n\t\t// in case there are no cookies at all. Also prevents odd result when\n\t\t// calling $.cookie().\n\t\tcookies = document.cookie ? document.cookie.split('; ') : [],\n\t\ti = 0,\n\t\tl = cookies.length;\n\t\tfor (; i < l; i++) {\n\t\t\tvar parts = cookies[i].split('='),\n\t\t\tname = decode(parts.shift()),\n\t\t\tcookie = parts.join('=');\n\t\t\tif (key === name) {\n\t\t\t\t// If second argument (value) is a function it's a converter...\n\t\t\t\tresult = read(cookie, value);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// Prevent storing a cookie that we couldn't decode.\n\t\t\tif (!key && (cookie = read(cookie)) !== undefined) {\n\t\t\t\tresult[name] = cookie;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t};\n\tconfig.defaults = {};\n\t$.removeCookie = function(key, options) {\n\t\t// Must not alter options, thus extending a fresh object...\n\t\t$.cookie(key, '', $.extend({},\n\t\toptions, {\n\t\t\texpires: -1\n\t\t}));\n\t\treturn ! $.cookie(key);\n\t};\n}));\n\n/* =======================================================================\n * jQuery.form.js Plugin v3.51.0 2014.06.20\n * Requires jQuery v1.5 or later\n * Copyright (c) 2014 M. Alsup\n * Examples and documentation at: http://malsup.com/jquery/form/\n * Project repository: https://github.com/malsup/form\n * Dual licensed under the MIT and GPL licenses.\n * https://github.com/malsup/form#copyright-and-license\n * ======================================================================== */\n// AMD support\n(function(factory) {\n\t\"use strict\";\n\tif (typeof define === 'function' && define.amd) {\n\t\t// using AMD; register as anon module\n\t\tdefine(['jquery'], factory);\n\t} else {\n\t\t// no AMD; invoke directly\n\t\tfactory((typeof(jQuery) != 'undefined') ? jQuery: window.Zepto);\n\t}\n} (function($) {\n\t\"use strict\";\n\t/*\n\t\t\tUsage Note:\n\t\t\t-----------\n\t\t\tDo not use both ajaxSubmit and ajaxForm on the same form.  These\n\t\t\tfunctions are mutually exclusive.  Use ajaxSubmit if you want\n\t\t\tto bind your own submit handler to the form.  For example,\n\t\t\n\t\t\t$(document).ready(function() {\n\t\t\t\t$('#myForm').on('submit', function(e) {\n\t\t\t\t\te.preventDefault(); // <-- important\n\t\t\t\t\t$(this).ajaxSubmit({\n\t\t\t\t\t\ttarget: '#output'\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t\n\t\t\tUse ajaxForm when you want the plugin to manage all the event binding\n\t\t\tfor you.  For example,\n\t\t\n\t\t\t$(document).ready(function() {\n\t\t\t\t$('#myForm').ajaxForm({\n\t\t\t\t\ttarget: '#output'\n\t\t\t\t});\n\t\t\t});\n\t\t\n\t\t\tYou can also use ajaxForm with delegation (requires jQuery v1.7+), so the\n\t\t\tform does not have to exist when you invoke ajaxForm:\n\t\t\n\t\t\t$('#myForm').ajaxForm({\n\t\t\t\tdelegation: true,\n\t\t\t\ttarget: '#output'\n\t\t\t});\n\t\t\n\t\t\tWhen using ajaxForm, the ajaxSubmit function will be invoked for you\n\t\t\tat the appropriate time.\n\t\t*/\n\t/**\n\t\t * Feature detection\n\t\t */\n\tvar feature = {};\n\tfeature.fileapi = $(\"<input type='file'/>\").get(0).files !== undefined;\n\tfeature.formdata = window.FormData !== undefined;\n\tvar hasProp = !!$.fn.prop;\n\t// attr2 uses prop when it can but checks the return type for\n\t// an expected string.  this accounts for the case where a form \n\t// contains inputs with names like \"action\" or \"method\"; in those\n\t// cases \"prop\" returns the element\n\t$.fn.attr2 = function() {\n\t\tif (!hasProp) {\n\t\t\treturn this.attr.apply(this, arguments);\n\t\t}\n\t\tvar val = this.prop.apply(this, arguments);\n\t\tif ((val && val.jquery) || typeof val === 'string') {\n\t\t\treturn val;\n\t\t}\n\t\treturn this.attr.apply(this, arguments);\n\t};\n\n\t/**\n\t\t * ajaxSubmit() provides a mechanism for immediately submitting\n\t\t * an HTML form using AJAX.\n\t\t */\n\t$.fn.ajaxSubmit = function(options) {\n\t\t/*jshint scripturl:true */\n\t\t// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)\n\t\tif (!this.length) {\n\t\t\tlog('ajaxSubmit: skipping submit process - no element selected');\n\t\t\treturn this;\n\t\t}\n\t\tvar method, action, url, $form = this;\n\t\tif (typeof options == 'function') {\n\t\t\toptions = {\n\t\t\t\tsuccess: options\n\t\t\t};\n\t\t} else if (options === undefined) {\n\t\t\toptions = {};\n\t\t}\n\t\tmethod = options.type || this.attr2('method');\n\t\taction = options.url || this.attr2('action');\n\t\turl = (typeof action === 'string') ? $.trim(action) : '';\n\t\turl = url || window.location.href || '';\n\t\tif (url) {\n\t\t\t// clean url (don't include hash vaue)\n\t\t\turl = (url.match(/^([^#]+)/) || [])[1];\n\t\t}\n\n\t\toptions = $.extend(true, {\n\t\t\turl: url,\n\t\t\tsuccess: $.ajaxSettings.success,\n\t\t\ttype: method || $.ajaxSettings.type,\n\t\t\tiframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false': 'about:blank'\n\t\t},\n\t\toptions);\n\n\t\t// hook for manipulating the form data before it is extracted;\n\t\t// convenient for use with rich editors like tinyMCE or FCKEditor\n\t\tvar veto = {};\n\t\tthis.trigger('form-pre-serialize', [this, options, veto]);\n\t\tif (veto.veto) {\n\t\t\tlog('ajaxSubmit: submit vetoed via form-pre-serialize trigger');\n\t\t\treturn this;\n\t\t}\n\n\t\t// provide opportunity to alter form data before it is serialized\n\t\tif (options.beforeSerialize && options.beforeSerialize(this, options) === false) {\n\t\t\tlog('ajaxSubmit: submit aborted via beforeSerialize callback');\n\t\t\treturn this;\n\t\t}\n\n\t\tvar traditional = options.traditional;\n\t\tif (traditional === undefined) {\n\t\t\ttraditional = $.ajaxSettings.traditional;\n\t\t}\n\n\t\tvar elements = [];\n\t\tvar qx, a = this.formToArray(options.semantic, elements);\n\t\tif (options.data) {\n\t\t\toptions.extraData = options.data;\n\t\t\tqx = $.param(options.data, traditional);\n\t\t}\n\n\t\t// give pre-submit callback an opportunity to abort the submit\n\t\tif (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {\n\t\t\tlog('ajaxSubmit: submit aborted via beforeSubmit callback');\n\t\t\treturn this;\n\t\t}\n\n\t\t// fire vetoable 'validate' event\n\t\tthis.trigger('form-submit-validate', [a, this, options, veto]);\n\t\tif (veto.veto) {\n\t\t\tlog('ajaxSubmit: submit vetoed via form-submit-validate trigger');\n\t\t\treturn this;\n\t\t}\n\n\t\tvar q = $.param(a, traditional);\n\t\tif (qx) {\n\t\t\tq = (q ? (q + '&' + qx) : qx);\n\t\t}\n\t\tif (options.type.toUpperCase() == 'GET') {\n\t\t\toptions.url += (options.url.indexOf('?') >= 0 ? '&': '?') + q;\n\t\t\toptions.data = null; // data is null for 'get'\n\t\t} else {\n\t\t\toptions.data = q; // data is the query string for 'post'\n\t\t}\n\n\t\tvar callbacks = [];\n\t\tif (options.resetForm) {\n\t\t\tcallbacks.push(function() {\n\t\t\t\t$form.resetForm();\n\t\t\t});\n\t\t}\n\t\tif (options.clearForm) {\n\t\t\tcallbacks.push(function() {\n\t\t\t\t$form.clearForm(options.includeHidden);\n\t\t\t});\n\t\t}\n\n\t\t// perform a load on the target only if dataType is not provided\n\t\tif (!options.dataType && options.target) {\n\t\t\tvar oldSuccess = options.success ||\n\t\t\tfunction() {};\n\t\t\tcallbacks.push(function(data) {\n\t\t\t\tvar fn = options.replaceTarget ? 'replaceWith': 'html';\n\t\t\t\t$(options.target)[fn](data).each(oldSuccess, arguments);\n\t\t\t});\n\t\t} else if (options.success) {\n\t\t\tcallbacks.push(options.success);\n\t\t}\n\n\t\toptions.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg\n\t\t\tvar context = options.context || this; // jQuery 1.4+ supports scope context\n\t\t\tfor (var i = 0,\n\t\t\tmax = callbacks.length; i < max; i++) {\n\t\t\t\tcallbacks[i].apply(context, [data, status, xhr || $form, $form]);\n\t\t\t}\n\t\t};\n\n\t\tif (options.error) {\n\t\t\tvar oldError = options.error;\n\t\t\toptions.error = function(xhr, status, error) {\n\t\t\t\tvar context = options.context || this;\n\t\t\t\toldError.apply(context, [xhr, status, error, $form]);\n\t\t\t};\n\t\t}\n\n\t\tif (options.complete) {\n\t\t\tvar oldComplete = options.complete;\n\t\t\toptions.complete = function(xhr, status) {\n\t\t\t\tvar context = options.context || this;\n\t\t\t\toldComplete.apply(context, [xhr, status, $form]);\n\t\t\t};\n\t\t}\n\n\t\t// are there files to upload?\n\t\t// [value] (issue #113), also see comment:\n\t\t// https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219\n\t\tvar fileInputs = $('input[type=file]:enabled', this).filter(function() {\n\t\t\treturn $(this).val() !== '';\n\t\t});\n\n\t\tvar hasFileInputs = fileInputs.length > 0;\n\t\tvar mp = 'multipart/form-data';\n\t\tvar multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);\n\n\t\tvar fileAPI = feature.fileapi && feature.formdata;\n\t\tlog(\"fileAPI :\" + fileAPI);\n\t\tvar shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;\n\n\t\tvar jqxhr;\n\n\t\t// options.iframe allows user to force iframe mode\n\t\t// 06-NOV-09: now defaulting to iframe mode if file input is detected\n\t\tif (options.iframe !== false && (options.iframe || shouldUseFrame)) {\n\t\t\t// hack to fix Safari hang (thanks to Tim Molendijk for this)\n\t\t\t// see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d\n\t\t\tif (options.closeKeepAlive) {\n\t\t\t\t$.get(options.closeKeepAlive,\n\t\t\t\tfunction() {\n\t\t\t\t\tjqxhr = fileUploadIframe(a);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tjqxhr = fileUploadIframe(a);\n\t\t\t}\n\t\t} else if ((hasFileInputs || multipart) && fileAPI) {\n\t\t\tjqxhr = fileUploadXhr(a);\n\t\t} else {\n\t\t\tjqxhr = $.ajax(options);\n\t\t}\n\n\t\t$form.removeData('jqxhr').data('jqxhr', jqxhr);\n\n\t\t// clear element array\n\t\tfor (var k = 0; k < elements.length; k++) {\n\t\t\telements[k] = null;\n\t\t}\n\n\t\t// fire 'notify' event\n\t\tthis.trigger('form-submit-notify', [this, options]);\n\t\treturn this;\n\n\t\t// utility fn for deep serialization\n\t\tfunction deepSerialize(extraData) {\n\t\t\tvar serialized = $.param(extraData, options.traditional).split('&');\n\t\t\tvar len = serialized.length;\n\t\t\tvar result = [];\n\t\t\tvar i, part;\n\t\t\tfor (i = 0; i < len; i++) {\n\t\t\t\t// #252; undo param space replacement\n\t\t\t\tserialized[i] = serialized[i].replace(/\\+/g, ' ');\n\t\t\t\tpart = serialized[i].split('=');\n\t\t\t\t// #278; use array instead of object storage, favoring array serializations\n\t\t\t\tresult.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\t// XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)\n\t\tfunction fileUploadXhr(a) {\n\t\t\tvar formdata = new FormData();\n\n\t\t\tfor (var i = 0; i < a.length; i++) {\n\t\t\t\tformdata.append(a[i].name, a[i].value);\n\t\t\t}\n\n\t\t\tif (options.extraData) {\n\t\t\t\tvar serializedData = deepSerialize(options.extraData);\n\t\t\t\tfor (i = 0; i < serializedData.length; i++) {\n\t\t\t\t\tif (serializedData[i]) {\n\t\t\t\t\t\tformdata.append(serializedData[i][0], serializedData[i][1]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toptions.data = null;\n\n\t\t\tvar s = $.extend(true, {},\n\t\t\t$.ajaxSettings, options, {\n\t\t\t\tcontentType: false,\n\t\t\t\tprocessData: false,\n\t\t\t\tcache: false,\n\t\t\t\ttype: method || 'POST'\n\t\t\t});\n\n\t\t\tif (options.uploadProgress) {\n\t\t\t\t// workaround because jqXHR does not expose upload property\n\t\t\t\ts.xhr = function() {\n\t\t\t\t\tvar xhr = $.ajaxSettings.xhr();\n\t\t\t\t\tif (xhr.upload) {\n\t\t\t\t\t\txhr.upload.addEventListener('progress',\n\t\t\t\t\t\tfunction(event) {\n\t\t\t\t\t\t\tvar percent = 0;\n\t\t\t\t\t\t\tvar position = event.loaded || event.position;\n\t\t\t\t\t\t\t/*event.position is deprecated*/\n\t\t\t\t\t\t\tvar total = event.total;\n\t\t\t\t\t\t\tif (event.lengthComputable) {\n\t\t\t\t\t\t\t\tpercent = Math.ceil(position / total * 100);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\toptions.uploadProgress(event, position, total, percent);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfalse);\n\t\t\t\t\t}\n\t\t\t\t\treturn xhr;\n\t\t\t\t};\n\t\t\t}\n\n\t\t\ts.data = null;\n\t\t\tvar beforeSend = s.beforeSend;\n\t\t\ts.beforeSend = function(xhr, o) {\n\t\t\t\t//Send FormData() provided by user\n\t\t\t\tif (options.formData) {\n\t\t\t\t\to.data = options.formData;\n\t\t\t\t} else {\n\t\t\t\t\to.data = formdata;\n\t\t\t\t}\n\t\t\t\tif (beforeSend) {\n\t\t\t\t\tbeforeSend.call(this, xhr, o);\n\t\t\t\t}\n\t\t\t};\n\t\t\treturn $.ajax(s);\n\t\t}\n\n\t\t// private function for handling file uploads (hat tip to YAHOO!)\n\t\tfunction fileUploadIframe(a) {\n\t\t\tvar form = $form[0],\n\t\t\tel,\n\t\t\ti,\n\t\t\ts,\n\t\t\tg,\n\t\t\tid,\n\t\t\t$io,\n\t\t\tio,\n\t\t\txhr,\n\t\t\tsub,\n\t\t\tn,\n\t\t\ttimedOut,\n\t\t\ttimeoutHandle;\n\t\t\tvar deferred = $.Deferred();\n\n\t\t\t// #341\n\t\t\tdeferred.abort = function(status) {\n\t\t\t\txhr.abort(status);\n\t\t\t};\n\n\t\t\tif (a) {\n\t\t\t\t// ensure that every serialized input is still enabled\n\t\t\t\tfor (i = 0; i < elements.length; i++) {\n\t\t\t\t\tel = $(elements[i]);\n\t\t\t\t\tif (hasProp) {\n\t\t\t\t\t\tel.prop('disabled', false);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tel.removeAttr('disabled');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ts = $.extend(true, {},\n\t\t\t$.ajaxSettings, options);\n\t\t\ts.context = s.context || s;\n\t\t\tid = 'jqFormIO' + (new Date().getTime());\n\t\t\tif (s.iframeTarget) {\n\t\t\t\t$io = $(s.iframeTarget);\n\t\t\t\tn = $io.attr2('name');\n\t\t\t\tif (!n) {\n\t\t\t\t\t$io.attr2('name', id);\n\t\t\t\t} else {\n\t\t\t\t\tid = n;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t$io = $('<iframe name=\"' + id + '\" src=\"' + s.iframeSrc + '\" />');\n\t\t\t\t$io.css({\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\ttop: '-1000px',\n\t\t\t\t\tleft: '-1000px'\n\t\t\t\t});\n\t\t\t}\n\t\t\tio = $io[0];\n\n\t\t\txhr = { // mock object\n\t\t\t\taborted: 0,\n\t\t\t\tresponseText: null,\n\t\t\t\tresponseXML: null,\n\t\t\t\tstatus: 0,\n\t\t\t\tstatusText: 'n/a',\n\t\t\t\tgetAllResponseHeaders: function() {},\n\t\t\t\tgetResponseHeader: function() {},\n\t\t\t\tsetRequestHeader: function() {},\n\t\t\t\tabort: function(status) {\n\t\t\t\t\tvar e = (status === 'timeout' ? 'timeout': 'aborted');\n\t\t\t\t\tlog('aborting upload... ' + e);\n\t\t\t\t\tthis.aborted = 1;\n\n\t\t\t\t\ttry { // #214, #257\n\t\t\t\t\t\tif (io.contentWindow.document.execCommand) {\n\t\t\t\t\t\t\tio.contentWindow.document.execCommand('Stop');\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch(ignore) {}\n\n\t\t\t\t\t$io.attr('src', s.iframeSrc); // abort op in progress\n\t\t\t\t\txhr.error = e;\n\t\t\t\t\tif (s.error) {\n\t\t\t\t\t\ts.error.call(s.context, xhr, e, status);\n\t\t\t\t\t}\n\t\t\t\t\tif (g) {\n\t\t\t\t\t\t$.event.trigger(\"ajaxError\", [xhr, s, e]);\n\t\t\t\t\t}\n\t\t\t\t\tif (s.complete) {\n\t\t\t\t\t\ts.complete.call(s.context, xhr, e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tg = s.global;\n\t\t\t// trigger ajax global events so that activity/block indicators work like normal\n\t\t\tif (g && 0 === $.active++) {\n\t\t\t\t$.event.trigger(\"ajaxStart\");\n\t\t\t}\n\t\t\tif (g) {\n\t\t\t\t$.event.trigger(\"ajaxSend\", [xhr, s]);\n\t\t\t}\n\n\t\t\tif (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {\n\t\t\t\tif (s.global) {\n\t\t\t\t\t$.active--;\n\t\t\t\t}\n\t\t\t\tdeferred.reject();\n\t\t\t\treturn deferred;\n\t\t\t}\n\t\t\tif (xhr.aborted) {\n\t\t\t\tdeferred.reject();\n\t\t\t\treturn deferred;\n\t\t\t}\n\n\t\t\t// add submitting element to data if we know it\n\t\t\tsub = form.clk;\n\t\t\tif (sub) {\n\t\t\t\tn = sub.name;\n\t\t\t\tif (n && !sub.disabled) {\n\t\t\t\t\ts.extraData = s.extraData || {};\n\t\t\t\t\ts.extraData[n] = sub.value;\n\t\t\t\t\tif (sub.type == \"image\") {\n\t\t\t\t\t\ts.extraData[n + '.x'] = form.clk_x;\n\t\t\t\t\t\ts.extraData[n + '.y'] = form.clk_y;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar CLIENT_TIMEOUT_ABORT = 1;\n\t\t\tvar SERVER_ABORT = 2;\n\n\t\t\tfunction getDoc(frame) {\n\t\t\t\t/* it looks like contentWindow or contentDocument do not\n\t\t\t\t\t * carry the protocol property in ie8, when running under ssl\n\t\t\t\t\t * frame.document is the only valid response document, since\n\t\t\t\t\t * the protocol is know but not on the other two objects. strange?\n\t\t\t\t\t * \"Same origin policy\" http://en.wikipedia.org/wiki/Same_origin_policy\n\t\t\t\t\t */\n\n\t\t\t\tvar doc = null;\n\n\t\t\t\t// IE8 cascading access check\n\t\t\t\ttry {\n\t\t\t\t\tif (frame.contentWindow) {\n\t\t\t\t\t\tdoc = frame.contentWindow.document;\n\t\t\t\t\t}\n\t\t\t\t} catch(err) {\n\t\t\t\t\t// IE8 access denied under ssl & missing protocol\n\t\t\t\t\tlog('cannot get iframe.contentWindow document: ' + err);\n\t\t\t\t}\n\n\t\t\t\tif (doc) { // successful getting content\n\t\t\t\t\treturn doc;\n\t\t\t\t}\n\n\t\t\t\ttry { // simply checking may throw in ie8 under ssl or mismatched protocol\n\t\t\t\t\tdoc = frame.contentDocument ? frame.contentDocument: frame.document;\n\t\t\t\t} catch(err) {\n\t\t\t\t\t// last attempt\n\t\t\t\t\tlog('cannot get iframe.contentDocument: ' + err);\n\t\t\t\t\tdoc = frame.document;\n\t\t\t\t}\n\t\t\t\treturn doc;\n\t\t\t}\n\n\t\t\t// Rails CSRF hack (thanks to Yvan Barthelemy)\n\t\t\tvar csrf_token = $('meta[name=csrf-token]').attr('content');\n\t\t\tvar csrf_param = $('meta[name=csrf-param]').attr('content');\n\t\t\tif (csrf_param && csrf_token) {\n\t\t\t\ts.extraData = s.extraData || {};\n\t\t\t\ts.extraData[csrf_param] = csrf_token;\n\t\t\t}\n\n\t\t\t// take a breath so that pending repaints get some cpu time before the upload starts\n\t\t\tfunction doSubmit() {\n\t\t\t\t// make sure form attrs are set\n\t\t\t\tvar t = $form.attr2('target'),\n\t\t\t\ta = $form.attr2('action'),\n\t\t\t\tmp = 'multipart/form-data',\n\t\t\t\tet = $form.attr('enctype') || $form.attr('encoding') || mp;\n\n\t\t\t\t// update form attrs in IE friendly way\n\t\t\t\tform.setAttribute('target', id);\n\t\t\t\tif (!method || /post/i.test(method)) {\n\t\t\t\t\tform.setAttribute('method', 'POST');\n\t\t\t\t}\n\t\t\t\tif (a != s.url) {\n\t\t\t\t\tform.setAttribute('action', s.url);\n\t\t\t\t}\n\n\t\t\t\t// ie borks in some cases when setting encoding\n\t\t\t\tif (!s.skipEncodingOverride && (!method || /post/i.test(method))) {\n\t\t\t\t\t$form.attr({\n\t\t\t\t\t\tencoding: 'multipart/form-data',\n\t\t\t\t\t\tenctype: 'multipart/form-data'\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// support timout\n\t\t\t\tif (s.timeout) {\n\t\t\t\t\ttimeoutHandle = setTimeout(function() {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tcb(CLIENT_TIMEOUT_ABORT);\n\t\t\t\t\t},\n\t\t\t\t\ts.timeout);\n\t\t\t\t}\n\n\t\t\t\t// look for server aborts\n\t\t\t\tfunction checkState() {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvar state = getDoc(io).readyState;\n\t\t\t\t\t\tlog('state = ' + state);\n\t\t\t\t\t\tif (state && state.toLowerCase() == 'uninitialized') {\n\t\t\t\t\t\t\tsetTimeout(checkState, 50);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\tlog('Server abort: ', e, ' (', e.name, ')');\n\t\t\t\t\t\tcb(SERVER_ABORT);\n\t\t\t\t\t\tif (timeoutHandle) {\n\t\t\t\t\t\t\tclearTimeout(timeoutHandle);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttimeoutHandle = undefined;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// add \"extra\" data to form if provided in options\n\t\t\t\tvar extraInputs = [];\n\t\t\t\ttry {\n\t\t\t\t\tif (s.extraData) {\n\t\t\t\t\t\tfor (var n in s.extraData) {\n\t\t\t\t\t\t\tif (s.extraData.hasOwnProperty(n)) {\n\t\t\t\t\t\t\t\t// if using the $.param format that allows for multiple values with the same name\n\t\t\t\t\t\t\t\tif ($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {\n\t\t\t\t\t\t\t\t\textraInputs.push($('<input type=\"hidden\" name=\"' + s.extraData[n].name + '\">').val(s.extraData[n].value).appendTo(form)[0]);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\textraInputs.push($('<input type=\"hidden\" name=\"' + n + '\">').val(s.extraData[n]).appendTo(form)[0]);\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\n\t\t\t\t\tif (!s.iframeTarget) {\n\t\t\t\t\t\t// add iframe to doc and submit the form\n\t\t\t\t\t\t$io.appendTo('body');\n\t\t\t\t\t}\n\t\t\t\t\tif (io.attachEvent) {\n\t\t\t\t\t\tio.attachEvent('onload', cb);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tio.addEventListener('load', cb, false);\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeout(checkState, 15);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tform.submit();\n\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\t// just in case form has element with name/id of 'submit'\n\t\t\t\t\t\tvar submitFn = document.createElement('form').submit;\n\t\t\t\t\t\tsubmitFn.apply(form);\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\t// reset attrs and remove \"extra\" input elements\n\t\t\t\t\tform.setAttribute('action', a);\n\t\t\t\t\tform.setAttribute('enctype', et); // #380\n\t\t\t\t\tif (t) {\n\t\t\t\t\t\tform.setAttribute('target', t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$form.removeAttr('target');\n\t\t\t\t\t}\n\t\t\t\t\t$(extraInputs).remove();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (s.forceSync) {\n\t\t\t\tdoSubmit();\n\t\t\t} else {\n\t\t\t\tsetTimeout(doSubmit, 10); // this lets dom updates render\n\t\t\t}\n\n\t\t\tvar data, doc, domCheckCount = 50,\n\t\t\tcallbackProcessed;\n\n\t\t\tfunction cb(e) {\n\t\t\t\tif (xhr.aborted || callbackProcessed) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tdoc = getDoc(io);\n\t\t\t\tif (!doc) {\n\t\t\t\t\tlog('cannot access response document');\n\t\t\t\t\te = SERVER_ABORT;\n\t\t\t\t}\n\t\t\t\tif (e === CLIENT_TIMEOUT_ABORT && xhr) {\n\t\t\t\t\txhr.abort('timeout');\n\t\t\t\t\tdeferred.reject(xhr, 'timeout');\n\t\t\t\t\treturn;\n\t\t\t\t} else if (e == SERVER_ABORT && xhr) {\n\t\t\t\t\txhr.abort('server abort');\n\t\t\t\t\tdeferred.reject(xhr, 'error', 'server abort');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!doc || doc.location.href == s.iframeSrc) {\n\t\t\t\t\t// response not received yet\n\t\t\t\t\tif (!timedOut) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (io.detachEvent) {\n\t\t\t\t\tio.detachEvent('onload', cb);\n\t\t\t\t} else {\n\t\t\t\t\tio.removeEventListener('load', cb, false);\n\t\t\t\t}\n\n\t\t\t\tvar status = 'success',\n\t\t\t\terrMsg;\n\t\t\t\ttry {\n\t\t\t\t\tif (timedOut) {\n\t\t\t\t\t\tthrow 'timeout';\n\t\t\t\t\t}\n\n\t\t\t\t\tvar isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);\n\t\t\t\t\tlog('isXml=' + isXml);\n\t\t\t\t\tif (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {\n\t\t\t\t\t\tif (--domCheckCount) {\n\t\t\t\t\t\t\t// in some browsers (Opera) the iframe DOM is not always traversable when\n\t\t\t\t\t\t\t// the onload callback fires, so we loop a bit to accommodate\n\t\t\t\t\t\t\tlog('requeing onLoad callback, DOM not available');\n\t\t\t\t\t\t\tsetTimeout(cb, 250);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// let this fall through because server response could be an empty document\n\t\t\t\t\t\t//log('Could not access iframe DOM after mutiple tries.');\n\t\t\t\t\t\t//throw 'DOMException: not available';\n\t\t\t\t\t}\n\n\t\t\t\t\t//log('response detected');\n\t\t\t\t\tvar docRoot = doc.body ? doc.body: doc.documentElement;\n\t\t\t\t\txhr.responseText = docRoot ? docRoot.innerHTML: null;\n\t\t\t\t\txhr.responseXML = doc.XMLDocument ? doc.XMLDocument: doc;\n\t\t\t\t\tif (isXml) {\n\t\t\t\t\t\ts.dataType = 'xml';\n\t\t\t\t\t}\n\t\t\t\t\txhr.getResponseHeader = function(header) {\n\t\t\t\t\t\tvar headers = {\n\t\t\t\t\t\t\t'content-type': s.dataType\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn headers[header.toLowerCase()];\n\t\t\t\t\t};\n\t\t\t\t\t// support for XHR 'status' & 'statusText' emulation :\n\t\t\t\t\tif (docRoot) {\n\t\t\t\t\t\txhr.status = Number(docRoot.getAttribute('status')) || xhr.status;\n\t\t\t\t\t\txhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar dt = (s.dataType || '').toLowerCase();\n\t\t\t\t\tvar scr = /(json|script|text)/.test(dt);\n\t\t\t\t\tif (scr || s.textarea) {\n\t\t\t\t\t\t// see if user embedded response in textarea\n\t\t\t\t\t\tvar ta = doc.getElementsByTagName('textarea')[0];\n\t\t\t\t\t\tif (ta) {\n\t\t\t\t\t\t\txhr.responseText = ta.value;\n\t\t\t\t\t\t\t// support for XHR 'status' & 'statusText' emulation :\n\t\t\t\t\t\t\txhr.status = Number(ta.getAttribute('status')) || xhr.status;\n\t\t\t\t\t\t\txhr.statusText = ta.getAttribute('statusText') || xhr.statusText;\n\t\t\t\t\t\t} else if (scr) {\n\t\t\t\t\t\t\t// account for browsers injecting pre around json response\n\t\t\t\t\t\t\tvar pre = doc.getElementsByTagName('pre')[0];\n\t\t\t\t\t\t\tvar b = doc.getElementsByTagName('body')[0];\n\t\t\t\t\t\t\tif (pre) {\n\t\t\t\t\t\t\t\txhr.responseText = pre.textContent ? pre.textContent: pre.innerText;\n\t\t\t\t\t\t\t} else if (b) {\n\t\t\t\t\t\t\t\txhr.responseText = b.textContent ? b.textContent: b.innerText;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {\n\t\t\t\t\t\txhr.responseXML = toXml(xhr.responseText);\n\t\t\t\t\t}\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tdata = httpData(xhr, dt, s);\n\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\tstatus = 'parsererror';\n\t\t\t\t\t\txhr.error = errMsg = (err || status);\n\t\t\t\t\t}\n\t\t\t\t} catch(err) {\n\t\t\t\t\tlog('error caught: ', err);\n\t\t\t\t\tstatus = 'error';\n\t\t\t\t\txhr.error = errMsg = (err || status);\n\t\t\t\t}\n\n\t\t\t\tif (xhr.aborted) {\n\t\t\t\t\tlog('upload aborted');\n\t\t\t\t\tstatus = null;\n\t\t\t\t}\n\n\t\t\t\tif (xhr.status) { // we've set xhr.status\n\t\t\t\t\tstatus = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success': 'error';\n\t\t\t\t}\n\n\t\t\t\t// ordering of these callbacks/triggers is odd, but that's how $.ajax does it\n\t\t\t\tif (status === 'success') {\n\t\t\t\t\tif (s.success) {\n\t\t\t\t\t\ts.success.call(s.context, data, 'success', xhr);\n\t\t\t\t\t}\n\t\t\t\t\tdeferred.resolve(xhr.responseText, 'success', xhr);\n\t\t\t\t\tif (g) {\n\t\t\t\t\t\t$.event.trigger(\"ajaxSuccess\", [xhr, s]);\n\t\t\t\t\t}\n\t\t\t\t} else if (status) {\n\t\t\t\t\tif (errMsg === undefined) {\n\t\t\t\t\t\terrMsg = xhr.statusText;\n\t\t\t\t\t}\n\t\t\t\t\tif (s.error) {\n\t\t\t\t\t\ts.error.call(s.context, xhr, status, errMsg);\n\t\t\t\t\t}\n\t\t\t\t\tdeferred.reject(xhr, 'error', errMsg);\n\t\t\t\t\tif (g) {\n\t\t\t\t\t\t$.event.trigger(\"ajaxError\", [xhr, s, errMsg]);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (g) {\n\t\t\t\t\t$.event.trigger(\"ajaxComplete\", [xhr, s]);\n\t\t\t\t}\n\n\t\t\t\tif (g && !--$.active) {\n\t\t\t\t\t$.event.trigger(\"ajaxStop\");\n\t\t\t\t}\n\n\t\t\t\tif (s.complete) {\n\t\t\t\t\ts.complete.call(s.context, xhr, status);\n\t\t\t\t}\n\n\t\t\t\tcallbackProcessed = true;\n\t\t\t\tif (s.timeout) {\n\t\t\t\t\tclearTimeout(timeoutHandle);\n\t\t\t\t}\n\n\t\t\t\t// clean up\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tif (!s.iframeTarget) {\n\t\t\t\t\t\t$io.remove();\n\t\t\t\t\t} else { //adding else to clean up existing iframe response.\n\t\t\t\t\t\t$io.attr('src', s.iframeSrc);\n\t\t\t\t\t}\n\t\t\t\t\txhr.responseXML = null;\n\t\t\t\t},\n\t\t\t\t100);\n\t\t\t}\n\n\t\t\tvar toXml = $.parseXML ||\n\t\t\tfunction(s, doc) { // use parseXML if available (jQuery 1.5+)\n\t\t\t\tif (window.ActiveXObject) {\n\t\t\t\t\tdoc = new ActiveXObject('Microsoft.XMLDOM');\n\t\t\t\t\tdoc.async = 'false';\n\t\t\t\t\tdoc.loadXML(s);\n\t\t\t\t} else {\n\t\t\t\t\tdoc = (new DOMParser()).parseFromString(s, 'text/xml');\n\t\t\t\t}\n\t\t\t\treturn (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc: null;\n\t\t\t};\n\t\t\tvar parseJSON = $.parseJSON ||\n\t\t\tfunction(s) {\n\t\t\t\t/*jslint evil:true */\n\t\t\t\treturn window['eval']('(' + s + ')');\n\t\t\t};\n\n\t\t\tvar httpData = function(xhr, type, s) { // mostly lifted from jq1.4.4\n\t\t\t\tvar ct = xhr.getResponseHeader('content-type') || '',\n\t\t\t\txml = type === 'xml' || !type && ct.indexOf('xml') >= 0,\n\t\t\t\tdata = xml ? xhr.responseXML: xhr.responseText;\n\n\t\t\t\tif (xml && data.documentElement.nodeName === 'parsererror') {\n\t\t\t\t\tif ($.error) {\n\t\t\t\t\t\t$.error('parsererror');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (s && s.dataFilter) {\n\t\t\t\t\tdata = s.dataFilter(data, type);\n\t\t\t\t}\n\t\t\t\tif (typeof data === 'string') {\n\t\t\t\t\tif (type === 'json' || !type && ct.indexOf('json') >= 0) {\n\t\t\t\t\t\tdata = parseJSON(data);\n\t\t\t\t\t} else if (type === \"script\" || !type && ct.indexOf(\"javascript\") >= 0) {\n\t\t\t\t\t\t$.globalEval(data);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn data;\n\t\t\t};\n\n\t\t\treturn deferred;\n\t\t}\n\t};\n\n\t/**\n\t\t * ajaxForm() provides a mechanism for fully automating form submission.\n\t\t *\n\t\t * The advantages of using this method instead of ajaxSubmit() are:\n\t\t *\n\t\t * 1: This method will include coordinates for <input type=\"image\" /> elements (if the element\n\t\t *    is used to submit the form).\n\t\t * 2. This method will include the submit element's name/value data (for the element that was\n\t\t *    used to submit the form).\n\t\t * 3. This method binds the submit() method to the form for you.\n\t\t *\n\t\t * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely\n\t\t * passes the options argument along after properly binding events for submit elements and\n\t\t * the form itself.\n\t\t */\n\t$.fn.ajaxForm = function(options) {\n\t\toptions = options || {};\n\t\toptions.delegation = options.delegation && $.isFunction($.fn.on);\n\n\t\t// in jQuery 1.3+ we can fix mistakes with the ready state\n\t\tif (!options.delegation && this.length === 0) {\n\t\t\tvar o = {\n\t\t\t\ts: this.selector,\n\t\t\t\tc: this.context\n\t\t\t};\n\t\t\tif (!$.isReady && o.s) {\n\t\t\t\tlog('DOM not ready, queuing ajaxForm');\n\t\t\t\t$(function() {\n\t\t\t\t\t$(o.s, o.c).ajaxForm(options);\n\t\t\t\t});\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\t// is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()\n\t\t\tlog('terminating; zero elements found by selector' + ($.isReady ? '': ' (DOM not ready)'));\n\t\t\treturn this;\n\t\t}\n\n\t\tif (options.delegation) {\n\t\t\t$(document).off('submit.form-plugin', this.selector, doAjaxSubmit).off('click.form-plugin', this.selector, captureSubmittingElement).on('submit.form-plugin', this.selector, options, doAjaxSubmit).on('click.form-plugin', this.selector, options, captureSubmittingElement);\n\t\t\treturn this;\n\t\t}\n\n\t\treturn this.ajaxFormUnbind().on('submit.form-plugin', options, doAjaxSubmit).on('click.form-plugin', options, captureSubmittingElement);\n\t};\n\n\t// private event handlers\n\tfunction doAjaxSubmit(e) {\n\t\t/*jshint validthis:true */\n\t\tvar options = e.data;\n\t\tif (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed\n\t\t\te.preventDefault();\n\t\t\t$(e.target).ajaxSubmit(options); // #365\n\t\t}\n\t}\n\n\tfunction captureSubmittingElement(e) {\n\t\t/*jshint validthis:true */\n\t\tvar target = e.target;\n\t\tvar $el = $(target);\n\t\tif (! ($el.is(\"[type=submit],[type=image]\"))) {\n\t\t\t// is this a child element of the submit el?  (ex: a span within a button)\n\t\t\tvar t = $el.closest('[type=submit]');\n\t\t\tif (t.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttarget = t[0];\n\t\t}\n\t\tvar form = this;\n\t\tform.clk = target;\n\t\tif (target.type == 'image') {\n\t\t\tif (e.offsetX !== undefined) {\n\t\t\t\tform.clk_x = e.offsetX;\n\t\t\t\tform.clk_y = e.offsetY;\n\t\t\t} else if (typeof $.fn.offset == 'function') {\n\t\t\t\tvar offset = $el.offset();\n\t\t\t\tform.clk_x = e.pageX - offset.left;\n\t\t\t\tform.clk_y = e.pageY - offset.top;\n\t\t\t} else {\n\t\t\t\tform.clk_x = e.pageX - target.offsetLeft;\n\t\t\t\tform.clk_y = e.pageY - target.offsetTop;\n\t\t\t}\n\t\t}\n\t\t// clear form vars\n\t\tsetTimeout(function() {\n\t\t\tform.clk = form.clk_x = form.clk_y = null;\n\t\t},\n\t\t100);\n\t}\n\n\t// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm\n\t$.fn.ajaxFormUnbind = function() {\n\t\treturn this.unbind('submit.form-plugin click.form-plugin');\n\t};\n\n\t/**\n\t\t * formToArray() gathers form element data into an array of objects that can\n\t\t * be passed to any of the following ajax functions: $.get, $.post, or load.\n\t\t * Each object in the array has both a 'name' and 'value' property.  An example of\n\t\t * an array for a simple login form might be:\n\t\t *\n\t\t * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]\n\t\t *\n\t\t * It is this array that is passed to pre-submit callback functions provided to the\n\t\t * ajaxSubmit() and ajaxForm() methods.\n\t\t */\n\t$.fn.formToArray = function(semantic, elements) {\n\t\tvar a = [];\n\t\tif (this.length === 0) {\n\t\t\treturn a;\n\t\t}\n\n\t\tvar form = this[0];\n\t\tvar formId = this.attr('id');\n\t\tvar els = semantic ? form.getElementsByTagName('*') : form.elements;\n\t\tvar els2;\n\n\t\tif (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390\n\t\t\tels = $(els).get(); // convert to standard array\n\t\t}\n\n\t\t// #386; account for inputs outside the form which use the 'form' attribute\n\t\tif (formId) {\n\t\t\tels2 = $(':input[form=\"' + formId + '\"]').get(); // hat tip @thet\n\t\t\tif (els2.length) {\n\t\t\t\tels = (els || []).concat(els2);\n\t\t\t}\n\t\t}\n\n\t\tif (!els || !els.length) {\n\t\t\treturn a;\n\t\t}\n\n\t\tvar i, j, n, v, el, max, jmax;\n\t\tfor (i = 0, max = els.length; i < max; i++) {\n\t\t\tel = els[i];\n\t\t\tn = el.name;\n\t\t\tif (!n || el.disabled) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (semantic && form.clk && el.type == \"image\") {\n\t\t\t\t// handle image inputs on the fly when semantic == true\n\t\t\t\tif (form.clk == el) {\n\t\t\t\t\ta.push({\n\t\t\t\t\t\tname: n,\n\t\t\t\t\t\tvalue: $(el).val(),\n\t\t\t\t\t\ttype: el.type\n\t\t\t\t\t});\n\t\t\t\t\ta.push({\n\t\t\t\t\t\tname: n + '.x',\n\t\t\t\t\t\tvalue: form.clk_x\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: n + '.y',\n\t\t\t\t\t\tvalue: form.clk_y\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tv = $.fieldValue(el, true);\n\t\t\tif (v && v.constructor == Array) {\n\t\t\t\tif (elements) {\n\t\t\t\t\telements.push(el);\n\t\t\t\t}\n\t\t\t\tfor (j = 0, jmax = v.length; j < jmax; j++) {\n\t\t\t\t\ta.push({\n\t\t\t\t\t\tname: n,\n\t\t\t\t\t\tvalue: v[j]\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (feature.fileapi && el.type == 'file') {\n\t\t\t\tif (elements) {\n\t\t\t\t\telements.push(el);\n\t\t\t\t}\n\t\t\t\tvar files = el.files;\n\t\t\t\tif (files.length) {\n\t\t\t\t\tfor (j = 0; j < files.length; j++) {\n\t\t\t\t\t\ta.push({\n\t\t\t\t\t\t\tname: n,\n\t\t\t\t\t\t\tvalue: files[j],\n\t\t\t\t\t\t\ttype: el.type\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// #180\n\t\t\t\t\ta.push({\n\t\t\t\t\t\tname: n,\n\t\t\t\t\t\tvalue: '',\n\t\t\t\t\t\ttype: el.type\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (v !== null && typeof v != 'undefined') {\n\t\t\t\tif (elements) {\n\t\t\t\t\telements.push(el);\n\t\t\t\t}\n\t\t\t\ta.push({\n\t\t\t\t\tname: n,\n\t\t\t\t\tvalue: v,\n\t\t\t\t\ttype: el.type,\n\t\t\t\t\trequired: el.required\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (!semantic && form.clk) {\n\t\t\t// input type=='image' are not found in elements array! handle it here\n\t\t\tvar $input = $(form.clk),\n\t\t\tinput = $input[0];\n\t\t\tn = input.name;\n\t\t\tif (n && !input.disabled && input.type == 'image') {\n\t\t\t\ta.push({\n\t\t\t\t\tname: n,\n\t\t\t\t\tvalue: $input.val()\n\t\t\t\t});\n\t\t\t\ta.push({\n\t\t\t\t\tname: n + '.x',\n\t\t\t\t\tvalue: form.clk_x\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: n + '.y',\n\t\t\t\t\tvalue: form.clk_y\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn a;\n\t};\n\n\t/**\n\t\t * Serializes form data into a 'submittable' string. This method will return a string\n\t\t * in the format: name1=value1&amp;name2=value2\n\t\t */\n\t$.fn.formSerialize = function(semantic) {\n\t\t//hand off to jQuery.param for proper encoding\n\t\treturn $.param(this.formToArray(semantic));\n\t};\n\n\t/**\n\t\t * Serializes all field elements in the jQuery object into a query string.\n\t\t * This method will return a string in the format: name1=value1&amp;name2=value2\n\t\t */\n\t$.fn.fieldSerialize = function(successful) {\n\t\tvar a = [];\n\t\tthis.each(function() {\n\t\t\tvar n = this.name;\n\t\t\tif (!n) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar v = $.fieldValue(this, successful);\n\t\t\tif (v && v.constructor == Array) {\n\t\t\t\tfor (var i = 0,\n\t\t\t\tmax = v.length; i < max; i++) {\n\t\t\t\t\ta.push({\n\t\t\t\t\t\tname: n,\n\t\t\t\t\t\tvalue: v[i]\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (v !== null && typeof v != 'undefined') {\n\t\t\t\ta.push({\n\t\t\t\t\tname: this.name,\n\t\t\t\t\tvalue: v\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\t//hand off to jQuery.param for proper encoding\n\t\treturn $.param(a);\n\t};\n\n\t/**\n\t\t * Returns the value(s) of the element in the matched set.  For example, consider the following form:\n\t\t *\n\t\t *  <form><fieldset>\n\t\t *      <input name=\"A\" type=\"text\" />\n\t\t *      <input name=\"A\" type=\"text\" />\n\t\t *      <input name=\"B\" type=\"checkbox\" value=\"B1\" />\n\t\t *      <input name=\"B\" type=\"checkbox\" value=\"B2\"/>\n\t\t *      <input name=\"C\" type=\"radio\" value=\"C1\" />\n\t\t *      <input name=\"C\" type=\"radio\" value=\"C2\" />\n\t\t *  </fieldset></form>\n\t\t *\n\t\t *  var v = $('input[type=text]').fieldValue();\n\t\t *  // if no values are entered into the text inputs\n\t\t *  v == ['','']\n\t\t *  // if values entered into the text inputs are 'foo' and 'bar'\n\t\t *  v == ['foo','bar']\n\t\t *\n\t\t *  var v = $('input[type=checkbox]').fieldValue();\n\t\t *  // if neither checkbox is checked\n\t\t *  v === undefined\n\t\t *  // if both checkboxes are checked\n\t\t *  v == ['B1', 'B2']\n\t\t *\n\t\t *  var v = $('input[type=radio]').fieldValue();\n\t\t *  // if neither radio is checked\n\t\t *  v === undefined\n\t\t *  // if first radio is checked\n\t\t *  v == ['C1']\n\t\t *\n\t\t * The successful argument controls whether or not the field element must be 'successful'\n\t\t * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).\n\t\t * The default value of the successful argument is true.  If this value is false the value(s)\n\t\t * for each element is returned.\n\t\t *\n\t\t * Note: This method *always* returns an array.  If no valid value can be determined the\n\t\t *    array will be empty, otherwise it will contain one or more values.\n\t\t */\n\t$.fn.fieldValue = function(successful) {\n\t\tfor (var val = [], i = 0, max = this.length; i < max; i++) {\n\t\t\tvar el = this[i];\n\t\t\tvar v = $.fieldValue(el, successful);\n\t\t\tif (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (v.constructor == Array) {\n\t\t\t\t$.merge(val, v);\n\t\t\t} else {\n\t\t\t\tval.push(v);\n\t\t\t}\n\t\t}\n\t\treturn val;\n\t};\n\n\t/**\n\t\t * Returns the value of the field element.\n\t\t */\n\t$.fieldValue = function(el, successful) {\n\t\tvar n = el.name,\n\t\tt = el.type,\n\t\ttag = el.tagName.toLowerCase();\n\t\tif (successful === undefined) {\n\t\t\tsuccessful = true;\n\t\t}\n\n\t\tif (successful && (!n || el.disabled || t == 'reset' || t == 'button' || (t == 'checkbox' || t == 'radio') && !el.checked || (t == 'submit' || t == 'image') && el.form && el.form.clk != el || tag == 'select' && el.selectedIndex == -1)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (tag == 'select') {\n\t\t\tvar index = el.selectedIndex;\n\t\t\tif (index < 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar a = [],\n\t\t\tops = el.options;\n\t\t\tvar one = (t == 'select-one');\n\t\t\tvar max = (one ? index + 1 : ops.length);\n\t\t\tfor (var i = (one ? index: 0); i < max; i++) {\n\t\t\t\tvar op = ops[i];\n\t\t\t\tif (op.selected) {\n\t\t\t\t\tvar v = op.value;\n\t\t\t\t\tif (!v) { // extra pain for IE...\n\t\t\t\t\t\tv = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text: op.value;\n\t\t\t\t\t}\n\t\t\t\t\tif (one) {\n\t\t\t\t\t\treturn v;\n\t\t\t\t\t}\n\t\t\t\t\ta.push(v);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn a;\n\t\t}\n\t\treturn $(el).val();\n\t};\n\n\t/**\n\t\t * Clears the form data.  Takes the following actions on the form's input fields:\n\t\t *  - input text fields will have their 'value' property set to the empty string\n\t\t *  - select elements will have their 'selectedIndex' property set to -1\n\t\t *  - checkbox and radio inputs will have their 'checked' property set to false\n\t\t *  - inputs of type submit, button, reset, and hidden will *not* be effected\n\t\t *  - button elements will *not* be effected\n\t\t */\n\t$.fn.clearForm = function(includeHidden) {\n\t\treturn this.each(function() {\n\t\t\t$('input,select,textarea', this).clearFields(includeHidden);\n\t\t});\n\t};\n\n\t/**\n\t\t * Clears the selected form elements.\n\t\t */\n\t$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {\n\t\tvar re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list\n\t\treturn this.each(function() {\n\t\t\tvar t = this.type,\n\t\t\ttag = this.tagName.toLowerCase();\n\t\t\tif (re.test(t) || tag == 'textarea') {\n\t\t\t\tthis.value = '';\n\t\t\t} else if (t == 'checkbox' || t == 'radio') {\n\t\t\t\tthis.checked = false;\n\t\t\t} else if (tag == 'select') {\n\t\t\t\tthis.selectedIndex = -1;\n\t\t\t} else if (t == \"file\") {\n\t\t\t\tif (/MSIE/.test(navigator.userAgent)) {\n\t\t\t\t\t$(this).replaceWith($(this).clone(true));\n\t\t\t\t} else {\n\t\t\t\t\t$(this).val('');\n\t\t\t\t}\n\t\t\t} else if (includeHidden) {\n\t\t\t\t// includeHidden can be the value true, or it can be a selector string\n\t\t\t\t// indicating a special test; for example:\n\t\t\t\t//  $('#myForm').clearForm('.special:hidden')\n\t\t\t\t// the above would clean hidden inputs that have the class of 'special'\n\t\t\t\tif ((includeHidden === true && /hidden/.test(t)) || (typeof includeHidden == 'string' && $(this).is(includeHidden))) {\n\t\t\t\t\tthis.value = '';\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t};\n\n\t/**\n\t\t * Resets the form data.  Causes all form elements to be reset to their original value.\n\t\t */\n\t$.fn.resetForm = function() {\n\t\treturn this.each(function() {\n\t\t\t// guard against an input with the name of 'reset'\n\t\t\t// note that IE reports the reset function as an 'object'\n\t\t\tif (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {\n\t\t\t\tthis.reset();\n\t\t\t}\n\t\t});\n\t};\n\n\t/**\n\t\t * Enables or disables any matching elements.\n\t\t */\n\t$.fn.enable = function(b) {\n\t\tif (b === undefined) {\n\t\t\tb = true;\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tthis.disabled = !b;\n\t\t});\n\t};\n\n\t/**\n\t\t * Checks/unchecks any matching checkboxes or radio buttons and\n\t\t * selects/deselects and matching option elements.\n\t\t */\n\t$.fn.selected = function(select) {\n\t\tif (select === undefined) {\n\t\t\tselect = true;\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tvar t = this.type;\n\t\t\tif (t == 'checkbox' || t == 'radio') {\n\t\t\t\tthis.checked = select;\n\t\t\t} else if (this.tagName.toLowerCase() == 'option') {\n\t\t\t\tvar $sel = $(this).parent('select');\n\t\t\t\tif (select && $sel[0] && $sel[0].type == 'select-one') {\n\t\t\t\t\t// deselect all other options\n\t\t\t\t\t$sel.find('option').selected(false);\n\t\t\t\t}\n\t\t\t\tthis.selected = select;\n\t\t\t}\n\t\t});\n\t};\n\n\t// expose debug var\n\t$.fn.ajaxSubmit.debug = false;\n\tfunction log() {\n\t\tif (!$.fn.ajaxSubmit.debug) {\n\t\t\treturn;\n\t\t}\n\t\tvar msg = '[jquery.form] ' + Array.prototype.join.call(arguments, '');\n\t\tif (window.console && window.console.log) {\n\t\t\twindow.console.log(msg);\n\t\t} else if (window.opera && window.opera.postError) {\n\t\t\twindow.opera.postError(msg);\n\t\t}\n\t}\n}));\n\n/* =======================================================================\n * jQuery.lazyload v1.9.3\n * Lazy Load - jQuery plugin for lazy loading images\n * Copyright (c) 2007-2013 Mika Tuupola\n * Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php\n * Project home: http://www.appelsiini.net/projects/lazyload\n * ======================================================================== */\n! (function($, window, document, undefined) {\n\tvar $window = $(window);\n\t$.fn.lazyload = function(options) {\n\t\tvar elements = this;\n\t\tvar $container;\n\t\tvar settings = {\n\t\t\tthreshold: 0,\n\t\t\tfailure_limit: 0,\n\t\t\tevent: \"scroll\",\n\t\t\teffect: \"show\",\n\t\t\tcontainer: window,\n\t\t\tdata_attribute: \"original\",\n\t\t\tskip_invisible: true,\n\t\t\tappear: null,\n\t\t\tload: null,\n\t\t\tplaceholder: \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC\"\n\t\t};\n\t\tfunction update() {\n\t\t\tvar counter = 0;\n\t\t\telements.each(function() {\n\t\t\t\tvar $this = $(this);\n\t\t\t\tif (settings.skip_invisible && !$this.is(\":visible\")) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif ($.abovethetop(this, settings) || $.leftofbegin(this, settings)) {\n\t\t\t\t\t/* Nothing. */\n\t\t\t\t} else if (!$.belowthefold(this, settings) && !$.rightoffold(this, settings)) {\n\t\t\t\t\t$this.trigger(\"appear\");\n\t\t\t\t\t/* if we found an image we'll load, reset the counter */\n\t\t\t\t\tcounter = 0;\n\t\t\t\t} else {\n\t\t\t\t\tif (++counter > settings.failure_limit) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tif (options) {\n\t\t\t/* Maintain BC for a couple of versions. */\n\t\t\tif (undefined !== options.failurelimit) {\n\t\t\t\toptions.failure_limit = options.failurelimit;\n\t\t\t\tdelete options.failurelimit;\n\t\t\t}\n\t\t\tif (undefined !== options.effectspeed) {\n\t\t\t\toptions.effect_speed = options.effectspeed;\n\t\t\t\tdelete options.effectspeed;\n\t\t\t}\n\t\t\t$.extend(settings, options);\n\t\t}\n\n\t\t/* Cache container as jQuery as object. */\n\t\t$container = (settings.container === undefined || settings.container === window) ? $window: $(settings.container);\n\n\t\t/* Fire one scroll event per scroll. Not one scroll event per image. */\n\t\tif (0 === settings.event.indexOf(\"scroll\")) {\n\t\t\t$container.on(settings.event,\n\t\t\tfunction() {\n\t\t\t\treturn update();\n\t\t\t});\n\t\t}\n\t\tthis.each(function() {\n\t\t\tvar self = this;\n\t\t\tvar $self = $(self);\n\t\t\tself.loaded = false;\n\n\t\t\t/* If no src attribute given use data:uri. */\n\t\t\tif ($self.attr(\"src\") === undefined || $self.attr(\"src\") === false) {\n\t\t\t\tif ($self.is(\"img\")) {\n\t\t\t\t\t$self.attr(\"src\", settings.placeholder);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* When appear is triggered load original image. */\n\t\t\t$self.one(\"appear\",\n\t\t\tfunction() {\n\t\t\t\tif (!this.loaded) {\n\t\t\t\t\tif (settings.appear) {\n\t\t\t\t\t\tvar elements_left = elements.length;\n\t\t\t\t\t\tsettings.appear.call(self, elements_left, settings);\n\t\t\t\t\t}\n\t\t\t\t\t$(\"<img />\").on(\"load\",\n\t\t\t\t\tfunction() {\n\t\t\t\t\t\tvar original = $self.attr(\"data-\" + settings.data_attribute);\n\t\t\t\t\t\t$self.hide();\n\t\t\t\t\t\tif ($self.is(\"img\")) {\n\t\t\t\t\t\t\t$self.attr(\"src\", original);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t$self.css(\"background-image\", \"url('\" + original + \"')\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$self[settings.effect](settings.effect_speed);\n\t\t\t\t\t\tself.loaded = true;\n\n\t\t\t\t\t\t/* Remove image from array so it is not looped next time. */\n\t\t\t\t\t\tvar temp = $.grep(elements,\n\t\t\t\t\t\tfunction(element) {\n\t\t\t\t\t\t\treturn ! element.loaded;\n\t\t\t\t\t\t});\n\t\t\t\t\t\telements = $(temp);\n\t\t\t\t\t\tif (settings.load) {\n\t\t\t\t\t\t\tvar elements_left = elements.length;\n\t\t\t\t\t\t\tsettings.load.call(self, elements_left, settings);\n\t\t\t\t\t\t}\n\t\t\t\t\t}).attr(\"src\", $self.attr(\"data-\" + settings.data_attribute));\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t/* When wanted event is triggered load original image */\n\t\t\t/* by triggering appear.                              */\n\t\t\tif (0 !== settings.event.indexOf(\"scroll\")) {\n\t\t\t\t$self.on(settings.event,\n\t\t\t\tfunction() {\n\t\t\t\t\tif (!self.loaded) {\n\t\t\t\t\t\t$self.trigger(\"appear\");\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\t/* Check if something appears when window is resized. */\n\t\t$window.on(\"resize\",\n\t\tfunction() {\n\t\t\tupdate();\n\t\t});\n\n\t\t/* With IOS5 force loading images when navigating with back button. */\n\t\t/* Non optimal workaround. */\n\t\tif ((/(?:iphone|ipod|ipad).*os 5/gi).test(navigator.appVersion)) {\n\t\t\t$window.on(\"pageshow\",\n\t\t\tfunction(event) {\n\t\t\t\tif (event.originalEvent && event.originalEvent.persisted) {\n\t\t\t\t\telements.each(function() {\n\t\t\t\t\t\t$(this).trigger(\"appear\");\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/* Force initial check if images should appear. */\n\t\t$(document).ready(function() {\n\t\t\tupdate();\n\t\t});\n\t\treturn this;\n\t};\n\n\t/* Convenience methods in jQuery namespace.           */\n\t/* Use as  $.belowthefold(element, {threshold : 100, container : window}) */\n\t$.belowthefold = function(element, settings) {\n\t\tvar fold;\n\t\tif (settings.container === undefined || settings.container === window) {\n\t\t\tfold = (window.innerHeight ? window.innerHeight: $window.height()) + $window.scrollTop();\n\t\t} else {\n\t\t\tfold = $(settings.container).offset().top + $(settings.container).height();\n\t\t}\n\t\treturn fold <= $(element).offset().top - settings.threshold;\n\t};\n\n\t$.rightoffold = function(element, settings) {\n\t\tvar fold;\n\t\tif (settings.container === undefined || settings.container === window) {\n\t\t\tfold = $window.width() + $window.scrollLeft();\n\t\t} else {\n\t\t\tfold = $(settings.container).offset().left + $(settings.container).width();\n\t\t}\n\t\treturn fold <= $(element).offset().left - settings.threshold;\n\t};\n\n\t$.abovethetop = function(element, settings) {\n\t\tvar fold;\n\t\tif (settings.container === undefined || settings.container === window) {\n\t\t\tfold = $window.scrollTop();\n\t\t} else {\n\t\t\tfold = $(settings.container).offset().top;\n\t\t}\n\t\treturn fold >= $(element).offset().top + settings.threshold + $(element).height();\n\t};\n\n\t$.leftofbegin = function(element, settings) {\n\t\tvar fold;\n\t\tif (settings.container === undefined || settings.container === window) {\n\t\t\tfold = $window.scrollLeft();\n\t\t} else {\n\t\t\tfold = $(settings.container).offset().left;\n\t\t}\n\t\treturn fold >= $(element).offset().left + settings.threshold + $(element).width();\n\t};\n\n\t$.inviewport = function(element, settings) {\n\t\treturn ! $.rightoffold(element, settings) && !$.leftofbegin(element, settings) && !$.belowthefold(element, settings) && !$.abovethetop(element, settings);\n\t};\n\n\t/* Custom selectors for your convenience.   */\n\t/* Use as $(\"img:below-the-fold\").something() or */\n\t/* $(\"img\").filter(\":below-the-fold\").something() which is faster */\n\t$.extend($.expr[\":\"], {\n\t\t\"below-the-fold\": function(a) {\n\t\t\treturn $.belowthefold(a, {\n\t\t\t\tthreshold: 0\n\t\t\t});\n\t\t},\n\t\t\"above-the-top\": function(a) {\n\t\t\treturn ! $.belowthefold(a, {\n\t\t\t\tthreshold: 0\n\t\t\t});\n\t\t},\n\t\t\"right-of-screen\": function(a) {\n\t\t\treturn $.rightoffold(a, {\n\t\t\t\tthreshold: 0\n\t\t\t});\n\t\t},\n\t\t\"left-of-screen\": function(a) {\n\t\t\treturn ! $.rightoffold(a, {\n\t\t\t\tthreshold: 0\n\t\t\t});\n\t\t},\n\t\t\"in-viewport\": function(a) {\n\t\t\treturn $.inviewport(a, {\n\t\t\t\tthreshold: 0\n\t\t\t});\n\t\t},\n\t\t/* Maintain BC for couple of versions. */\n\t\t\"above-the-fold\": function(a) {\n\t\t\treturn ! $.belowthefold(a, {\n\t\t\t\tthreshold: 0\n\t\t\t});\n\t\t},\n\t\t\"right-of-fold\": function(a) {\n\t\t\treturn $.rightoffold(a, {\n\t\t\t\tthreshold: 0\n\t\t\t});\n\t\t},\n\t\t\"left-of-fold\": function(a) {\n\t\t\treturn ! $.rightoffold(a, {\n\t\t\t\tthreshold: 0\n\t\t\t});\n\t\t}\n\t});\n})(jQuery, window, document);\n\n/* =======================================================================\n* jQuery.responsive-nav.js v1.0.39\n* https://github.com/viljamis/responsive-nav.js\n* http://responsive-nav.com\n*\n* Copyright (c) 2015 @viljamis\n* Available under the MIT license\n * ======================================================================== */\n/* global Event */\n(function(document, window, index) {\n\t// Index is used to keep multiple navs on the same page namespaced\n\t\"use strict\";\n\tvar responsiveNav = function(el, options) {\n\t\tvar computed = !!window.getComputedStyle;\n\n\t\t/**\n\t\t* getComputedStyle polyfill for old browsers\n\t\t*/\n\t\tif (!computed) {\n\t\t\twindow.getComputedStyle = function(el) {\n\t\t\t\tthis.el = el;\n\t\t\t\tthis.getPropertyValue = function(prop) {\n\t\t\t\t\tvar re = /(\\-([a-z]){1})/g;\n\t\t\t\t\tif (prop === \"float\") {\n\t\t\t\t\t\tprop = \"styleFloat\";\n\t\t\t\t\t}\n\t\t\t\t\tif (re.test(prop)) {\n\t\t\t\t\t\tprop = prop.replace(re,\n\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\treturn arguments[2].toUpperCase();\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn el.currentStyle[prop] ? el.currentStyle[prop] : null;\n\t\t\t\t};\n\t\t\t\treturn this;\n\t\t\t};\n\t\t}\n\t\t/* exported addEvent, removeEvent, getChildren, setAttributes, addClass, removeClass, forEach */\n\n\t\t/**\n\t\t* Add Event\n\t\t* fn arg can be an object or a function, thanks to handleEvent\n\t\t* read more at: http://www.thecssninja.com/javascript/handleevent\n\t\t*\n\t\t* @param  {element}  element\n\t\t* @param  {event}    event\n\t\t* @param  {Function} fn\n\t\t* @param  {boolean}  bubbling\n\t\t*/\n\t\tvar addEvent = function(el, evt, fn, bubble) {\n\t\t\tif (\"addEventListener\" in el) {\n\t\t\t\t// BBOS6 doesn't support handleEvent, catch and polyfill\n\t\t\t\ttry {\n\t\t\t\t\tel.addEventListener(evt, fn, bubble);\n\t\t\t\t} catch(e) {\n\t\t\t\t\tif (typeof fn === \"object\" && fn.handleEvent) {\n\t\t\t\t\t\tel.addEventListener(evt,\n\t\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\t\t// Bind fn as this and set first arg as event object\n\t\t\t\t\t\t\tfn.handleEvent.call(fn, e);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbubble);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (\"attachEvent\" in el) {\n\t\t\t\t// check if the callback is an object and contains handleEvent\n\t\t\t\tif (typeof fn === \"object\" && fn.handleEvent) {\n\t\t\t\t\tel.attachEvent(\"on\" + evt,\n\t\t\t\t\tfunction() {\n\t\t\t\t\t\t// Bind fn as this\n\t\t\t\t\t\tfn.handleEvent.call(fn);\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tel.attachEvent(\"on\" + evt, fn);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t* Remove Event\n\t*\n\t* @param  {element}  element\n\t* @param  {event}    event\n\t* @param  {Function} fn\n\t* @param  {boolean}  bubbling\n\t*/\n\t\tremoveEvent = function(el, evt, fn, bubble) {\n\t\t\tif (\"removeEventListener\" in el) {\n\t\t\t\ttry {\n\t\t\t\t\tel.removeEventListener(evt, fn, bubble);\n\t\t\t\t} catch(e) {\n\t\t\t\t\tif (typeof fn === \"object\" && fn.handleEvent) {\n\t\t\t\t\t\tel.removeEventListener(evt,\n\t\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\t\tfn.handleEvent.call(fn, e);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbubble);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (\"detachEvent\" in el) {\n\t\t\t\tif (typeof fn === \"object\" && fn.handleEvent) {\n\t\t\t\t\tel.detachEvent(\"on\" + evt,\n\t\t\t\t\tfunction() {\n\t\t\t\t\t\tfn.handleEvent.call(fn);\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tel.detachEvent(\"on\" + evt, fn);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t* Get the children of any element\n\t*\n\t* @param  {element}\n\t* @return {array} Returns matching elements in an array\n\t*/\n\t\tgetChildren = function(e) {\n\t\t\tif (e.children.length < 1) {\n\t\t\t\tthrow new Error(\"The Nav container has no containing elements\");\n\t\t\t}\n\t\t\t// Store all children in array\n\t\t\tvar children = [];\n\t\t\t// Loop through children and store in array if child != TextNode\n\t\t\tfor (var i = 0; i < e.children.length; i++) {\n\t\t\t\tif (e.children[i].nodeType === 1) {\n\t\t\t\t\tchildren.push(e.children[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn children;\n\t\t},\n\n\t\t/**\n\t* Sets multiple attributes at once\n\t*\n\t* @param {element} element\n\t* @param {attrs}   attrs\n\t*/\n\t\tsetAttributes = function(el, attrs) {\n\t\t\tfor (var key in attrs) {\n\t\t\t\tel.setAttribute(key, attrs[key]);\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t* Adds a class to any element\n\t*\n\t* @param {element} element\n\t* @param {string}  class\n\t*/\n\t\taddClass = function(el, cls) {\n\t\t\tif (el.className.indexOf(cls) !== 0) {\n\t\t\t\tel.className += \" \" + cls;\n\t\t\t\tel.className = el.className.replace(/(^\\s*)|(\\s*$)/g, \"\");\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t* Remove a class from any element\n\t*\n\t* @param  {element} element\n\t* @param  {string}  class\n\t*/\n\t\tremoveClass = function(el, cls) {\n\t\t\tvar reg = new RegExp(\"(\\\\s|^)\" + cls + \"(\\\\s|$)\");\n\t\t\tel.className = el.className.replace(reg, \" \").replace(/(^\\s*)|(\\s*$)/g, \"\");\n\t\t},\n\n\t\t/**\n\t* forEach method that passes back the stuff we need\n\t*\n\t* @param  {array}    array\n\t* @param  {Function} callback\n\t* @param  {scope}    scope\n\t*/\n\t\tforEach = function(array, callback, scope) {\n\t\t\tfor (var i = 0; i < array.length; i++) {\n\t\t\t\tcallback.call(scope, i, array[i]);\n\t\t\t}\n\t\t};\n\n\t\tvar nav, opts, navToggle, styleElement = document.createElement(\"style\"),\n\t\thtmlEl = document.documentElement,\n\t\thasAnimFinished,\n\t\tisMobile,\n\t\tnavOpen;\n\n\t\tvar ResponsiveNav = function(el, options) {\n\t\t\tvar i;\n\n\t\t\t/**\n\t\t* Default options\n\t\t* @type {Object}\n\t\t*/\n\t\t\tthis.options = {\n\t\t\t\tanimate: true,\n\t\t\t\t// Boolean: Use CSS3 transitions, true or false\n\t\t\t\ttransition: 284,\n\t\t\t\t// Integer: Speed of the transition, in milliseconds\n\t\t\t\tlabel: \"Menu\",\n\t\t\t\t// String: Label for the navigation toggle\n\t\t\t\tinsert: \"before\",\n\t\t\t\t// String: Insert the toggle before or after the navigation\n\t\t\t\tcustomToggle: \"\",\n\t\t\t\t// Selector: Specify the ID of a custom toggle\n\t\t\t\tcloseOnNavClick: false,\n\t\t\t\t// Boolean: Close the navigation when one of the links are clicked\n\t\t\t\topenPos: \"relative\",\n\t\t\t\t// String: Position of the opened nav, relative or static\n\t\t\t\tnavClass: \"nav-collapse\",\n\t\t\t\t// String: Default CSS class. If changed, you need to edit the CSS too!\n\t\t\t\tnavActiveClass: \"js-nav-active\",\n\t\t\t\t// String: Class that is added to <html> element when nav is active\n\t\t\t\tjsClass: \"js\",\n\t\t\t\t// String: 'JS enabled' class which is added to <html> element\n\t\t\t\tinit: function() {},\n\t\t\t\t// Function: Init callback\n\t\t\t\topen: function() {},\n\t\t\t\t// Function: Open callback\n\t\t\t\tclose: function() {} // Function: Close callback\n\t\t\t};\n\n\t\t\t// User defined options\n\t\t\tfor (i in options) {\n\t\t\t\tthis.options[i] = options[i];\n\t\t\t}\n\n\t\t\t// Adds \"js\" class for <html>\n\t\t\taddClass(htmlEl, this.options.jsClass);\n\n\t\t\t// Wrapper\n\t\t\tthis.wrapperEl = el.replace(\"#\", \"\");\n\n\t\t\t// Try selecting ID first\n\t\t\tif (document.getElementById(this.wrapperEl)) {\n\t\t\t\tthis.wrapper = document.getElementById(this.wrapperEl);\n\n\t\t\t\t// If element with an ID doesn't exist, use querySelector\n\t\t\t} else if (document.querySelector(this.wrapperEl)) {\n\t\t\t\tthis.wrapper = document.querySelector(this.wrapperEl);\n\n\t\t\t\t// If element doesn't exists, stop here.\n\t\t\t} else {\n\t\t\t\tthrow new Error(\"The nav element you are trying to select doesn't exist\");\n\t\t\t}\n\n\t\t\t// Inner wrapper\n\t\t\tthis.wrapper.inner = getChildren(this.wrapper);\n\n\t\t\t// For minification\n\t\t\topts = this.options;\n\t\t\tnav = this.wrapper;\n\n\t\t\t// Init\n\t\t\tthis._init(this);\n\t\t};\n\n\t\tResponsiveNav.prototype = {\n\n\t\t\t/**\n\t\t* Unattaches events and removes any classes that were added\n\t\t*/\n\t\t\tdestroy: function() {\n\t\t\t\tthis._removeStyles();\n\t\t\t\tremoveClass(nav, \"closed\");\n\t\t\t\tremoveClass(nav, \"opened\");\n\t\t\t\tremoveClass(nav, opts.navClass);\n\t\t\t\tremoveClass(nav, opts.navClass + \"-\" + this.index);\n\t\t\t\tremoveClass(htmlEl, opts.navActiveClass);\n\t\t\t\tnav.removeAttribute(\"style\");\n\t\t\t\tnav.removeAttribute(\"aria-hidden\");\n\n\t\t\t\tremoveEvent(window, \"resize\", this, false);\n\t\t\t\tremoveEvent(window, \"focus\", this, false);\n\t\t\t\tremoveEvent(document.body, \"touchmove\", this, false);\n\t\t\t\tremoveEvent(navToggle, \"touchstart\", this, false);\n\t\t\t\tremoveEvent(navToggle, \"touchend\", this, false);\n\t\t\t\tremoveEvent(navToggle, \"mouseup\", this, false);\n\t\t\t\tremoveEvent(navToggle, \"keyup\", this, false);\n\t\t\t\tremoveEvent(navToggle, \"click\", this, false);\n\n\t\t\t\tif (!opts.customToggle) {\n\t\t\t\t\tnavToggle.parentNode.removeChild(navToggle);\n\t\t\t\t} else {\n\t\t\t\t\tnavToggle.removeAttribute(\"aria-hidden\");\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Toggles the navigation open/close\n\t\t*/\n\t\t\ttoggle: function() {\n\t\t\t\tif (hasAnimFinished === true) {\n\t\t\t\t\tif (!navOpen) {\n\t\t\t\t\t\tthis.open();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Opens the navigation\n\t\t*/\n\t\t\topen: function() {\n\t\t\t\tif (!navOpen) {\n\t\t\t\t\tremoveClass(nav, \"closed\");\n\t\t\t\t\taddClass(nav, \"opened\");\n\t\t\t\t\taddClass(htmlEl, opts.navActiveClass);\n\t\t\t\t\taddClass(navToggle, \"active\");\n\t\t\t\t\tnav.style.position = opts.openPos;\n\t\t\t\t\tsetAttributes(nav, {\n\t\t\t\t\t\t\"aria-hidden\": \"false\"\n\t\t\t\t\t});\n\t\t\t\t\tnavOpen = true;\n\t\t\t\t\topts.open();\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Closes the navigation\n\t\t*/\n\t\t\tclose: function() {\n\t\t\t\tif (navOpen) {\n\t\t\t\t\taddClass(nav, \"closed\");\n\t\t\t\t\tremoveClass(nav, \"opened\");\n\t\t\t\t\tremoveClass(htmlEl, opts.navActiveClass);\n\t\t\t\t\tremoveClass(navToggle, \"active\");\n\t\t\t\t\tsetAttributes(nav, {\n\t\t\t\t\t\t\"aria-hidden\": \"true\"\n\t\t\t\t\t});\n\n\t\t\t\t\t// If animations are enabled, wait until they finish\n\t\t\t\t\tif (opts.animate) {\n\t\t\t\t\t\thasAnimFinished = false;\n\t\t\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t\t\tnav.style.position = \"absolute\";\n\t\t\t\t\t\t\thasAnimFinished = true;\n\t\t\t\t\t\t},\n\t\t\t\t\t\topts.transition + 10);\n\n\t\t\t\t\t\t// Animations aren't enabled, we can do these immediately\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnav.style.position = \"absolute\";\n\t\t\t\t\t}\n\n\t\t\t\t\tnavOpen = false;\n\t\t\t\t\topts.close();\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Resize is called on window resize and orientation change.\n\t\t* It initializes the CSS styles and height calculations.\n\t\t*/\n\t\t\tresize: function() {\n\n\t\t\t\t// Resize watches navigation toggle's display state\n\t\t\t\tif (window.getComputedStyle(navToggle, null).getPropertyValue(\"display\") !== \"none\") {\n\n\t\t\t\t\tisMobile = true;\n\t\t\t\t\tsetAttributes(navToggle, {\n\t\t\t\t\t\t\"aria-hidden\": \"false\"\n\t\t\t\t\t});\n\n\t\t\t\t\t// If the navigation is hidden\n\t\t\t\t\tif (nav.className.match(/(^|\\s)closed(\\s|$)/)) {\n\t\t\t\t\t\tsetAttributes(nav, {\n\t\t\t\t\t\t\t\"aria-hidden\": \"true\"\n\t\t\t\t\t\t});\n\t\t\t\t\t\tnav.style.position = \"absolute\";\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._createStyles();\n\t\t\t\t\tthis._calcHeight();\n\t\t\t\t} else {\n\t\t\t\t\tisMobile = false;\n\t\t\t\t\tsetAttributes(navToggle, {\n\t\t\t\t\t\t\"aria-hidden\": \"true\"\n\t\t\t\t\t});\n\t\t\t\t\tsetAttributes(nav, {\n\t\t\t\t\t\t\"aria-hidden\": \"false\"\n\t\t\t\t\t});\n\t\t\t\t\tnav.style.position = opts.openPos;\n\t\t\t\t\tthis._removeStyles();\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Takes care of all even handling\n\t\t*\n\t\t* @param  {event} event\n\t\t* @return {type} returns the type of event that should be used\n\t\t*/\n\t\t\thandleEvent: function(e) {\n\t\t\t\tvar evt = e || window.event;\n\t\t\t\tswitch (evt.type) {\n\t\t\t\tcase \"touchstart\":\n\t\t\t\t\tthis._onTouchStart(evt);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"touchmove\":\n\t\t\t\t\tthis._onTouchMove(evt);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"touchend\":\n\t\t\t\tcase \"mouseup\":\n\t\t\t\t\tthis._onTouchEnd(evt);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"click\":\n\t\t\t\t\tthis._preventDefault(evt);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"keyup\":\n\t\t\t\t\tthis._onKeyUp(evt);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"focus\":\n\t\t\t\tcase \"resize\":\n\t\t\t\t\tthis.resize(evt);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Initializes the widget\n\t\t*/\n\t\t\t_init: function() {\n\t\t\t\tthis.index = index++;\n\n\t\t\t\taddClass(nav, opts.navClass);\n\t\t\t\taddClass(nav, opts.navClass + \"-\" + this.index);\n\t\t\t\taddClass(nav, \"closed\");\n\t\t\t\thasAnimFinished = true;\n\t\t\t\tnavOpen = false;\n\n\t\t\t\tthis._closeOnNavClick();\n\t\t\t\tthis._createToggle();\n\t\t\t\tthis._transitions();\n\t\t\t\tthis.resize();\n\n\t\t\t\t/**\n\t\t\t* On IE8 the resize event triggers too early for some reason\n\t\t\t* so it's called here again on init to make sure all the\n\t\t\t* calculated styles are correct.\n\t\t\t*/\n\t\t\t\tvar self = this;\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tself.resize();\n\t\t\t\t},\n\t\t\t\t20);\n\n\t\t\t\taddEvent(window, \"resize\", this, false);\n\t\t\t\taddEvent(window, \"focus\", this, false);\n\t\t\t\taddEvent(document.body, \"touchmove\", this, false);\n\t\t\t\taddEvent(navToggle, \"touchstart\", this, false);\n\t\t\t\taddEvent(navToggle, \"touchend\", this, false);\n\t\t\t\taddEvent(navToggle, \"mouseup\", this, false);\n\t\t\t\taddEvent(navToggle, \"keyup\", this, false);\n\t\t\t\taddEvent(navToggle, \"click\", this, false);\n\n\t\t\t\t/**\n\t\t\t* Init callback here\n\t\t\t*/\n\t\t\t\topts.init();\n\t\t\t},\n\n\t\t\t/**\n\t\t* Creates Styles to the <head>\n\t\t*/\n\t\t\t_createStyles: function() {\n\t\t\t\tif (!styleElement.parentNode) {\n\t\t\t\t\tstyleElement.type = \"text/css\";\n\t\t\t\t\tdocument.getElementsByTagName(\"head\")[0].appendChild(styleElement);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Removes styles from the <head>\n\t\t*/\n\t\t\t_removeStyles: function() {\n\t\t\t\tif (styleElement.parentNode) {\n\t\t\t\t\tstyleElement.parentNode.removeChild(styleElement);\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Creates Navigation Toggle\n\t\t*/\n\t\t\t_createToggle: function() {\n\t\t\t\t// If there's no toggle, let's create one\n\t\t\t\tif (!opts.customToggle) {\n\t\t\t\t\tvar toggle = document.createElement(\"a\");\n\t\t\t\t\ttoggle.innerHTML = opts.label;\n\t\t\t\t\tsetAttributes(toggle, {\n\t\t\t\t\t\t\"href\": \"#\",\n\t\t\t\t\t\t\"class\": \"nav-toggle\"\n\t\t\t\t\t});\n\n\t\t\t\t\t// Determine where to insert the toggle\n\t\t\t\t\tif (opts.insert === \"after\") {\n\t\t\t\t\t\tnav.parentNode.insertBefore(toggle, nav.nextSibling);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnav.parentNode.insertBefore(toggle, nav);\n\t\t\t\t\t}\n\n\t\t\t\t\tnavToggle = toggle;\n\n\t\t\t\t\t// There is a toggle already, let's use that one\n\t\t\t\t} else {\n\t\t\t\t\tvar toggleEl = opts.customToggle.replace(\"#\", \"\");\n\n\t\t\t\t\tif (document.getElementById(toggleEl)) {\n\t\t\t\t\t\tnavToggle = document.getElementById(toggleEl);\n\t\t\t\t\t} else if (document.querySelector(toggleEl)) {\n\t\t\t\t\t\tnavToggle = document.querySelector(toggleEl);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new Error(\"The custom nav toggle you are trying to select doesn't exist\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Closes the navigation when a link inside is clicked.\n\t\t*/\n\t\t\t_closeOnNavClick: function() {\n\t\t\t\tif (opts.closeOnNavClick) {\n\t\t\t\t\tvar links = nav.getElementsByTagName(\"a\"),\n\t\t\t\t\tself = this;\n\t\t\t\t\tforEach(links,\n\t\t\t\t\tfunction(i, el) {\n\t\t\t\t\t\taddEvent(links[i], \"click\",\n\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\tif (isMobile) {\n\t\t\t\t\t\t\t\tself.toggle();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfalse);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Prevents the default functionality.\n\t\t*\n\t\t* @param  {event} event\n\t\t*/\n\t\t\t_preventDefault: function(e) {\n\t\t\t\tif (e.preventDefault) {\n\t\t\t\t\tif (e.stopImmediatePropagation) {\n\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t}\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t\treturn false;\n\n\t\t\t\t\t// This is strictly for old IE\n\t\t\t\t} else {\n\t\t\t\t\te.returnValue = false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* On touch start we get the location of the touch.\n\t\t*\n\t\t* @param  {event} event\n\t\t*/\n\t\t\t_onTouchStart: function(e) {\n\t\t\t\tif (!Event.prototype.stopImmediatePropagation) {\n\t\t\t\t\tthis._preventDefault(e);\n\t\t\t\t}\n\t\t\t\tthis.startX = e.touches[0].clientX;\n\t\t\t\tthis.startY = e.touches[0].clientY;\n\t\t\t\tthis.touchHasMoved = false;\n\n\t\t\t\t/**\n\t\t\t* Remove mouseup event completely here to avoid\n\t\t\t* double triggering the event.\n\t\t\t*/\n\t\t\t\tremoveEvent(navToggle, \"mouseup\", this, false);\n\t\t\t},\n\n\t\t\t/**\n\t\t* Check if the user is scrolling instead of tapping.\n\t\t*\n\t\t* @param  {event} event\n\t\t*/\n\t\t\t_onTouchMove: function(e) {\n\t\t\t\tif (Math.abs(e.touches[0].clientX - this.startX) > 10 || Math.abs(e.touches[0].clientY - this.startY) > 10) {\n\t\t\t\t\tthis.touchHasMoved = true;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* On touch end toggle the navigation.\n\t\t*\n\t\t* @param  {event} event\n\t\t*/\n\t\t\t_onTouchEnd: function(e) {\n\t\t\t\tthis._preventDefault(e);\n\t\t\t\tif (!isMobile) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// If the user isn't scrolling\n\t\t\t\tif (!this.touchHasMoved) {\n\n\t\t\t\t\t// If the event type is touch\n\t\t\t\t\tif (e.type === \"touchend\") {\n\t\t\t\t\t\tthis.toggle();\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t// Event type was click, not touch\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar evt = e || window.event;\n\n\t\t\t\t\t\t// If it isn't a right click, do toggling\n\t\t\t\t\t\tif (! (evt.which === 3 || evt.button === 2)) {\n\t\t\t\t\t\t\tthis.toggle();\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\t/**\n\t\t* For keyboard accessibility, toggle the navigation on Enter\n\t\t* keypress too.\n\t\t*\n\t\t* @param  {event} event\n\t\t*/\n\t\t\t_onKeyUp: function(e) {\n\t\t\t\tvar evt = e || window.event;\n\t\t\t\tif (evt.keyCode === 13) {\n\t\t\t\t\tthis.toggle();\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Adds the needed CSS transitions if animations are enabled\n\t\t*/\n\t\t\t_transitions: function() {\n\t\t\t\tif (opts.animate) {\n\t\t\t\t\tvar objStyle = nav.style,\n\t\t\t\t\ttransition = \"max-height \" + opts.transition + \"ms\";\n\t\t\t\t\tobjStyle.WebkitTransition = objStyle.MozTransition = objStyle.OTransition = objStyle.transition = transition;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t/**\n\t\t* Calculates the height of the navigation and then creates\n\t\t* styles which are later added to the page <head>\n\t\t*/\n\t\t\t_calcHeight: function() {\n\t\t\t\tvar savedHeight = 0;\n\t\t\t\tfor (var i = 0; i < nav.inner.length; i++) {\n\t\t\t\t\tsavedHeight += nav.inner[i].offsetHeight;\n\t\t\t\t}\n\t\t\t\tvar innerStyles = \".\" + opts.jsClass + \" .\" + opts.navClass + \"-\" + this.index + \".opened{max-height:\" + savedHeight + \"px !important} .\" + opts.jsClass + \" .\" + opts.navClass + \"-\" + this.index + \".opened.dropdown-active {max-height:9999px !important}\";\n\t\t\t\tif (styleElement.styleSheet) {\n\t\t\t\t\tstyleElement.styleSheet.cssText = innerStyles;\n\t\t\t\t} else {\n\t\t\t\t\tstyleElement.innerHTML = innerStyles;\n\t\t\t\t}\n\t\t\t\tinnerStyles = \"\";\n\t\t\t}\n\t\t};\n\t\t/**\n\t\t* Return new Responsive Nav\n\t\t*/\n\t\treturn new ResponsiveNav(el, options);\n\t};\n\tif (typeof module !== \"undefined\" && module.exports) {\n\t\tmodule.exports = responsiveNav;\n\t} else {\n\t\twindow.responsiveNav = responsiveNav;\n\t}\n} (document, window, 0));\n\n/* =======================================================================\n * jQuery.placeholder.js 兼容性处理\n * ======================================================================== */\n!function(window, document, $) {\n\tvar isInputSupported = 'placeholder' in document.createElement('input');\n\tvar isTextareaSupported = 'placeholder' in document.createElement('textarea');\n\tvar prototype = $.fn;\n\tvar valHooks = $.valHooks;\n\tvar propHooks = $.propHooks;\n\tvar hooks;\n\tvar placeholder;\n\n\tif (isInputSupported && isTextareaSupported) {\n\t\tplaceholder = prototype.placeholder = function() {\n\t\t\treturn this;\n\t\t};\n\t\tplaceholder.input = placeholder.textarea = true;\n\t} else {\n\t\tplaceholder = prototype.placeholder = function() {\n\t\t\tvar $this = this;\n\t\t\t$this.filter((isInputSupported ? 'textarea': ':input') + '[placeholder]').not('.placeholder').on({\n\t\t\t\t'focus.placeholder': clearPlaceholder,\n\t\t\t\t'blur.placeholder': setPlaceholder\n\t\t\t}).data('placeholder-enabled', true).trigger('blur.placeholder');\n\t\t\treturn $this;\n\t\t};\n\t\tplaceholder.input = isInputSupported;\n\t\tplaceholder.textarea = isTextareaSupported;\n\t\thooks = {\n\t\t\t'get': function(element) {\n\t\t\t\tvar $element = $(element);\n\t\t\t\tvar $passwordInput = $element.data('placeholder-password');\n\t\t\t\tif ($passwordInput) {\n\t\t\t\t\treturn $passwordInput[0].value;\n\t\t\t\t}\n\t\t\t\treturn $element.data('placeholder-enabled') && $element.hasClass('placeholder') ? '': element.value;\n\t\t\t},\n\t\t\t'set': function(element, value) {\n\t\t\t\tvar $element = $(element);\n\t\t\t\tvar $passwordInput = $element.data('placeholder-password');\n\t\t\t\tif ($passwordInput) {\n\t\t\t\t\treturn $passwordInput[0].value = value;\n\t\t\t\t}\n\t\t\t\tif (!$element.data('placeholder-enabled')) {\n\t\t\t\t\treturn element.value = value;\n\t\t\t\t}\n\t\t\t\tif (value == '') {\n\t\t\t\t\telement.value = value;\n\t\t\t\t\tif (element != safeActiveElement()) {\n\t\t\t\t\t\tsetPlaceholder.call(element);\n\t\t\t\t\t}\n\t\t\t\t} else if ($element.hasClass('placeholder')) {\n\t\t\t\t\tclearPlaceholder.call(element, true, value) || (element.value = value);\n\t\t\t\t} else {\n\t\t\t\t\telement.value = value;\n\t\t\t\t}\n\t\t\t\treturn $element;\n\t\t\t}\n\t\t};\n\n\t\tif (!isInputSupported) {\n\t\t\tvalHooks.input = hooks;\n\t\t\tpropHooks.value = hooks;\n\t\t}\n\t\tif (!isTextareaSupported) {\n\t\t\tvalHooks.textarea = hooks;\n\t\t\tpropHooks.value = hooks;\n\t\t}\n\n\t\t$(function() {\n\t\t\t$(document).delegate('form', 'submit.placeholder',\n\t\t\tfunction() {\n\t\t\t\tvar $inputs = $('.placeholder', this).each(clearPlaceholder);\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t$inputs.each(setPlaceholder);\n\t\t\t\t},\n\t\t\t\t10);\n\t\t\t});\n\t\t});\n\n\t\t$(window).on('beforeunload.placeholder',\n\t\tfunction() {\n\t\t\t$('.placeholder').each(function() {\n\t\t\t\tthis.value = '';\n\t\t\t});\n\t\t});\n\t}\n\n\tfunction args(elem) {\n\t\tvar newAttrs = {};\n\t\tvar rinlinejQuery = /^jQuery\\d+$/;\n\t\t$.each(elem.attributes,\n\t\tfunction(i, attr) {\n\t\t\tif (attr.specified && !rinlinejQuery.test(attr.name)) {\n\t\t\t\tnewAttrs[attr.name] = attr.value;\n\t\t\t}\n\t\t});\n\t\treturn newAttrs;\n\t}\n\n\tfunction clearPlaceholder(event, value) {\n\t\tvar input = this;\n\t\tvar $input = $(input);\n\t\tif (input.value == $input.attr('placeholder') && $input.hasClass('placeholder')) {\n\t\t\tif ($input.data('placeholder-password')) {\n\t\t\t\t$input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id'));\n\t\t\t\tif (event === true) {\n\t\t\t\t\treturn $input[0].value = value;\n\t\t\t\t}\n\t\t\t\t$input.focus();\n\t\t\t} else {\n\t\t\t\tinput.value = '';\n\t\t\t\t$input.removeClass('placeholder');\n\t\t\t\tinput == safeActiveElement() && input.select();\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction setPlaceholder() {\n\t\tvar $replacement;\n\t\tvar input = this;\n\t\tvar $input = $(input);\n\t\tvar id = this.id;\n\t\tif (input.value == '') {\n\t\t\tif (input.type == 'password') {\n\t\t\t\tif (!$input.data('placeholder-textinput')) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t$replacement = $input.clone().prop('type', 'text');\n\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t$replacement = $('<input>').prop($.extend(args(this), {\n\t\t\t\t\t\t\t'type': 'text'\n\t\t\t\t\t\t}));\n\t\t\t\t\t}\n\t\t\t\t\t$replacement.removeAttr('name').data({\n\t\t\t\t\t\t'placeholder-password': $input,\n\t\t\t\t\t\t'placeholder-id': id\n\t\t\t\t\t}).on('focus.placeholder', clearPlaceholder);\n\t\t\t\t\t$input.data({\n\t\t\t\t\t\t'placeholder-textinput': $replacement,\n\t\t\t\t\t\t'placeholder-id': id\n\t\t\t\t\t}).before($replacement);\n\t\t\t\t}\n\t\t\t\t$input = $input.removeAttr('id').hide().prev().attr('id', id).show();\n\t\t\t}\n\t\t\t$input.addClass('placeholder');\n\t\t\t$input[0].value = $input.attr('placeholder');\n\t\t} else {\n\t\t\t$input.removeClass('placeholder');\n\t\t}\n\t}\n\tfunction safeActiveElement() {\n\t\ttry {\n\t\t\treturn document.activeElement;\n\t\t} catch(exception) {}\n\t}\n} (this, document, jQuery);\n\n/* =======================================================================\n * jquery.emailsuggest.js v1.0 邮箱自动提示\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n!function($) {\n\tvar\n\t// 插件名 \n\tplugin = 'emailsuggest',\n\n\t// 默认参数配置\n\tdefaults = {\n\t\tsugClass: 'emailSug',\n\t\tdomains: ['163.com', '126.com', 'sohu.com', '139.com', 'sina.com', 'qq.com', 'gmail.com']\n\t};\n\n\tfunction EmailSug(elem, options) {\n\t\tthis.$field = $(elem);\n\t\tthis.options = $.extend(true, {},\n\t\tdefaults, options);\n\t\tthis._defaults = defaults;\n\t\tthis._domains = this.options.domains;\n\t\t// 当前选中元素下标\n\t\tthis.selectedIndex = 0;\n\n\t\tthis.init();\n\t}\n\n\tEmailSug.prototype = {\n\t\tinit: function() {\n\t\t\tthis.addEvent();\n\t\t},\n\n\t\taddEvent: function() {\n\t\t\tvar that = this,\n\t\t\tvalue;\n\n\t\t\tthis.$field.on('keyup.ema',\n\t\t\tfunction(e) {\n\t\t\t\tvalue = $.trim(this.value);\n\n\t\t\t\tif (value) {\n\t\t\t\t\tthat.create(this, value);\n\t\t\t\t\tthat.doSelect(e.keyCode);\n\t\t\t\t} else {\n\t\t\t\t\tthat.hide();\n\t\t\t\t}\n\t\t\t}).on('blur.ema',\n\t\t\tfunction() {\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tthat.hide();\n\t\t\t\t},\n\t\t\t\t200);\n\t\t\t});\n\t\t},\n\t\tcreate: function(elem, value) {\n\t\t\tvar that = this,\n\t\t\tarr, len, fragment, ul = [],\n\t\t\toffset,\n\t\t\tleft,\n\t\t\ttop,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tstyle,\n\t\t\t// 左右边框 \n\t\t\tborderWidth = 2;\n\n\t\t\telem = $(elem);\n\t\t\toffset = elem.offset();\n\t\t\twidth = elem.outerWidth(true) - borderWidth;\n\t\t\theight = elem.outerHeight(true);\n\t\t\tleft = offset.left;\n\t\t\ttop = offset.top + height;\n\t\t\tstyle = 'left: ' + left + 'px; top: ' + top + 'px; width: ' + width + 'px; border: 1px solid #e2e2e2; border-top: 0; display: none';\n\t\t\tfragment = $('<div class=\"' + this.options.sugClass + '-wrapper\" style=\"' + style + '\" />');\n\t\t\tul.push('<ul class=\"' + this.options.sugClass + '-list\">');\n\n\t\t\tarr = this.filter(value, this._domains);\n\t\t\tlen = arr.length;\n\t\t\t$.each(arr,\n\t\t\tfunction(i, domain) {\n\t\t\t\tvar _class = that.options.sugClass + '-item';\n\n\t\t\t\tif (that.selectedIndex > len - 1) {\n\t\t\t\t\tif (i === 0) {\n\t\t\t\t\t\t_class += ' active';\n\t\t\t\t\t\tthat.selectedIndex = 0;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (i === that.selectedIndex) {\n\t\t\t\t\t\t_class += ' active';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tul.push('<li class=\"' + _class + '\" data-index=\"' + i + '\">' + value.replace(/@.*/, '') + '@' + domain + '</li>');\n\t\t\t});\n\n\t\t\tul.push('</ul>');\n\t\t\tul = ul.join('');\n\t\t\tif (this.$suggest) {\n\t\t\t\tthis.$suggest.empty();\n\t\t\t\tthis.$suggest.append(ul);\n\t\t\t} else {\n\t\t\t\tfragment.append(ul);\n\t\t\t\t// 显示到页面\n\t\t\t\t$('body').append(fragment);\n\t\t\t\tthis.$suggest = fragment;\n\t\t\t\tthis.$suggest.on('mouseenter click', '.' + this.options.sugClass + '-item',\n\t\t\t\tfunction(e) {\n\t\t\t\t\tvar lis, li;\n\t\t\t\t\tli = $(this);\n\t\t\t\t\tlis = li.parent().children();\n\t\t\t\t\tif (e.type === 'mouseenter') {\n\t\t\t\t\t\tli.addClass('active').siblings().removeClass('active');\n\t\t\t\t\t\tthat.selectedIndex = $.inArray(this, lis);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// 当前选中\n\t\t\t\t\t\tthat.$field.val(lis.eq(that.selectedIndex).text());\n\t\t\t\t\t\t// 隐藏email sug\n\t\t\t\t\t\tthat.hide();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\tthis.show();\n\t\t},\n\n\t\tdoSelect: function(keyCode) {\n\t\t\tvar elems = $('.' + this.options.sugClass + '-item', this.$suggest),\n\t\t\tmin = 0,\n\t\t\tmax = elems.length - 1;\n\t\t\tswitch (keyCode) {\n\t\t\tcase 13:\n\t\t\t\t// 回车选中当前已选项\n\t\t\t\t$('li.active', this.$suggest).trigger('click');\n\n\t\t\t\t// 下标重置\n\t\t\t\tthis.selectedIndex = 0;\n\n\t\t\t\tbreak;\n\t\t\t\t// 向上\n\t\t\tcase 38:\n\t\t\t\tthis.selectedIndex--;\n\n\t\t\t\tif (this.selectedIndex < min) {\n\t\t\t\t\tthis.selectedIndex = max;\n\t\t\t\t}\n\n\t\t\t\telems.removeClass('active').eq(this.selectedIndex).addClass('active');\n\t\t\t\tbreak;\n\t\t\t\t// 向下 \n\t\t\tcase 40:\n\t\t\t\tthis.selectedIndex++;\n\n\t\t\t\tif (this.selectedIndex > max) {\n\t\t\t\t\tthis.selectedIndex = min;\n\t\t\t\t}\n\n\t\t\t\telems.removeClass('active').eq(this.selectedIndex).addClass('active');\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t},\n\t\tfilter: function(value, arr) {\n\t\t\tvar start, suffix, r = [];\n\n\t\t\tstart = value.indexOf('@');\n\t\t\tif (start > -1) {\n\t\t\t\tsuffix = value.substring(start + 1);\n\t\t\t\t$.each(arr,\n\t\t\t\tfunction(i, str) {\n\t\t\t\t\tif (str.indexOf(suffix) > -1) {\n\t\t\t\t\t\tr.push(str);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tr = arr;\n\t\t\t}\n\t\t\treturn r;\n\t\t},\n\t\tshow: function() {\n\t\t\tif (this.$suggest) {\n\t\t\t\tthis.$suggest.show();\n\t\t\t}\n\t\t},\n\n\t\thide: function() {\n\t\t\tif (this.$suggest) {\n\t\t\t\tthis.$suggest.hide();\n\t\t\t}\n\t\t}\n\t}\n\n\t$.fn[plugin] = function(options) {\n\t\treturn this.each(function() {\n\t\t\tif (!$.data(this, plugin)) {\n\t\t\t\t$.data(this, plugin, new EmailSug(this, options));\n\t\t\t}\n\t\t});\n\t}\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huispinner.js v2.1.2 微调器\n * http://www.h-ui.net/\n * Created & Modified by guojunhui\n * Date modified 2017.06.26\n *\n * Copyright 2017 北京颖杰联创科技有限公司 All rights reserved.\n * Licensed under MIT license.\n * http://opensource.org/licenses/MIT\n * ========================================================================*/\n!function($) {\t\n\t$.fn.Huispinner = function(options, callback) {\n\t\tvar defaults = {\n\t\t\tvalue : 1,\n\t\t\tminValue : 1,\n\t\t\tmaxValue : 999,\n\t\t\tdis : 1,\n\t\t}\n\t\tvar options = $.extend(defaults, options);\n\t\tvar keyCodes = {\n\t\t\tup : 38,\n\t\t\tdown : 40\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\tvar that = $(this);\n\t\t\tvar str = '<div class=\"spinner\">'\n\t\t\t\t\t+ '<a class=\"subtract\" href=\"javascript:void(0)\"><i>-</i></a>'\n\t\t\t\t\t+ '<input class=\"amount input-text\" value=\"'\n\t\t\t\t\t+ options.value + '\" autocomplete=\"off\">'\n\t\t\t\t\t+ '<a class=\"add\" href=\"javascript:void(0)\"><i>+</i></a>'\n\t\t\t\t\t+ '</div>';\n\t\t\tthat.append(str);\n\n\t\t\tvar input = that.find(\".input-text\"),\n\t\t\t\tsubtract = that.find(\".subtract\"),\n\t\t\t\tadd = that.find(\".add\"),\n\t\t\t\tvalue = parseInt(input.val());\n\n\t\t\tif (value <= options.minValue) {\n\t\t\t\tsubtract.addClass(\"disabled\");\n\t\t\t\tadd.removeClass(\"disabled\");\n\t\t\t}\n\t\t\tif (value >= options.maxValue) {\n\t\t\t\tsubtract.removeClass(\"disabled\");\n\t\t\t\tadd.addClass(\"disabled\");\n\t\t\t}\n\n\t\t\t// 输入框失去焦点\n\t\t\tinput.on('blur', function() {\n\t\t\t\tvar v = $(this).val();\n\t\t\t\tv = v.replace(/[^\\d]/g, \"\");\n\t\t\t\tv = v.replace(/\\b(0+)/gi, \"\");\n\n\t\t\t\tif (v != \"\") {\n\t\t\t\t\tif (v > options.minValue && v < options.maxValue) {\n\t\t\t\t\t\tinput.val(v)\n\t\t\t\t\t\tadd.removeClass(\"disabled\");\n\t\t\t\t\t\tsubtract.removeClass(\"disabled\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (v <= options.minValue) {\n\t\t\t\t\t\t\tinput.val(options.minValue);\n\t\t\t\t\t\t\tsubtract.addClass(\"disabled\");\n\t\t\t\t\t\t\tadd.removeClass(\"disabled\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinput.val(options.maxValue);\n\t\t\t\t\t\t\tsubtract.removeClass(\"disabled\");\n\t\t\t\t\t\t\tadd.addClass(\"disabled\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t$(this).val(options.minValue);\n\t\t\t\t\tsubtract.addClass(\"disabled\");\n\t\t\t\t\tadd.removeClass(\"disabled\");\n\t\t\t\t}\n\t\t\t\tif (callback) {\n\t\t\t\t\tcallback(input.val());\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// 上下方向键\n\t\t\tinput.on(\"keydown\", function(e) {\n\t\t\t\tvar evt = e || window.event;\n\t\t\t\tif (evt.keyCode === keyCodes.up) {\n\t\t\t\t\tsubtract.trigger(\"click\");\n\t\t\t\t\tevt.returnValue = false;\n\t\t\t\t}\n\t\t\t\tif (evt.keyCode === keyCodes.down) {\n\t\t\t\t\tadd.trigger(\"click\");\n\t\t\t\t\tevt.returnValue = false;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// 减\n\t\t\tsubtract.on('click', function() {\n\t\t\t\tvar goodsCount = parseInt(input.val());\n\t\t\t\tinput.val(goodsCount <= options.minValue\n\t\t\t\t\t\t? options.minValue\n\t\t\t\t\t\t: goodsCount - options.dis);\n\t\t\t\tadd.removeClass(\"disabled\");\n\t\t\t\tif (input.val() <= options.minValue) {\n\t\t\t\t\tinput.val(options.minValue)\n\t\t\t\t\tsubtract.addClass(\"disabled\");\n\t\t\t\t}\n\t\t\t\tif (callback) {\n\t\t\t\t\tcallback(input.val());\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// 加\n\t\t\tadd.on('click', function() {\n\t\t\t\tvar goodsCount = parseInt(input.val());\n\t\t\t\tinput.val(goodsCount >= options.maxValue\n\t\t\t\t\t\t? options.maxValue\n\t\t\t\t\t\t: goodsCount + options.dis);\n\t\t\t\tsubtract.removeClass(\"disabled\");\n\n\t\t\t\tif (input.val() >= options.maxValue) {\n\t\t\t\t\tinput.val(options.maxValue);\n\t\t\t\t\tadd.addClass(\"disabled\");\n\t\t\t\t}\n\t\t\t\tif (callback) {\n\t\t\t\t\tcallback(input.val());\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n}(window.jQuery);\n\n/* =======================================================================\n * jQuery.format.js 金额格式化\n * ========================================================================*/\n!function($) {\n\t$.extend({\n\t\tformat: function(str, step, splitor) {\n\t\t\tstr = str.toString();\n\t\t\tvar len = str.length;\n\n\t\t\tif (len > step) {\n\t\t\t\tvar l1 = len % step,\n\t\t\t\tl2 = parseInt(len / step),\n\t\t\t\tarr = [],\n\t\t\t\tfirst = str.substr(0, l1);\n\t\t\t\tif (first != '') {\n\t\t\t\t\tarr.push(first);\n\t\t\t\t};\n\t\t\t\tfor (var i = 0; i < l2; i++) {\n\t\t\t\t\tarr.push(str.substr(l1 + i * step, step));\n\t\t\t\t};\n\t\t\t\tstr = arr.join(splitor);\n\t\t\t};\n\t\t\treturn str;\n\t\t}\n\t});\n} (window.jQuery);\n\n/* =======================================================================\n * jquery.togglePassword.js 隐藏显示密码\n * type=\"password\"\n * ========================================================================*/\n!function($) {\n\t$.fn.togglePassword = function(options) {\n\t\tvar s = $.extend($.fn.togglePassword.defaults, options),\n\t\tinput = $(this);\n\n\t\t$(s.el).on(s.ev,\n\t\tfunction() {\n\t\t\t\"password\" == $(input).attr(\"type\") ? $(input).attr(\"type\", \"text\") : $(input).attr(\"type\", \"password\");\n\t\t});\n\t};\n\n\t$.fn.togglePassword.defaults = {\n\t\tev: \"click\"\n\t};\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.iCheck.js v1.0.2, http://git.io/arlzeA\n * Powerful jQuery and Zepto plugin for checkboxes and radio buttons customization\n *\n * (c) 2013 Damir Sultanov, http://fronteed.com\n * MIT Licensed\n * ======================================================================== */\n!(function($) {\n\t// Cached vars\n\tvar _iCheck = 'iCheck',\n\t_iCheckHelper = _iCheck + '-helper',\n\t_checkbox = 'checkbox',\n\t_radio = 'radio',\n\t_checked = 'checked',\n\t_unchecked = 'un' + _checked,\n\t_disabled = 'disabled',\n\t_determinate = 'determinate',\n\t_indeterminate = 'in' + _determinate,\n\t_update = 'update',\n\t_type = 'type',\n\t_click = 'click',\n\t_touch = 'touchbegin.i touchend.i',\n\t_add = 'addClass',\n\t_remove = 'removeClass',\n\t_callback = 'trigger',\n\t_label = 'label',\n\t_cursor = 'cursor',\n\t_mobile = /ipad|iphone|ipod|android|blackberry|windows phone|opera mini|silk/i.test(navigator.userAgent);\n\n\t// Plugin init\n\t$.fn[_iCheck] = function(options, fire) {\n\t\t// Walker\n\t\tvar handle = 'input[type=\"' + _checkbox + '\"], input[type=\"' + _radio + '\"]',\n\t\tstack = $(),\n\t\twalker = function(object) {\n\t\t\tobject.each(function() {\n\t\t\t\tvar self = $(this);\n\n\t\t\t\tif (self.is(handle)) {\n\t\t\t\t\tstack = stack.add(self);\n\t\t\t\t} else {\n\t\t\t\t\tstack = stack.add(self.find(handle));\n\t\t\t\t}\n\t\t\t});\n\t\t};\n\n\t\t// Check if we should operate with some method\n\t\tif (/^(check|uncheck|toggle|indeterminate|determinate|disable|enable|update|destroy)$/i.test(options)) {\n\n\t\t\t// Normalize method's name\n\t\t\toptions = options.toLowerCase();\n\n\t\t\t// Find checkboxes and radio buttons\n\t\t\twalker(this);\n\n\t\t\treturn stack.each(function() {\n\t\t\t\tvar self = $(this);\n\n\t\t\t\tif (options == 'destroy') {\n\t\t\t\t\ttidy(self, 'ifDestroyed');\n\t\t\t\t} else {\n\t\t\t\t\toperate(self, true, options);\n\t\t\t\t}\n\n\t\t\t\t// Fire method's callback\n\t\t\t\tif ($.isFunction(fire)) {\n\t\t\t\t\tfire();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// Customization\n\t\t} else if (typeof options == 'object' || !options) {\n\n\t\t\t// Check if any options were passed\n\t\t\tvar settings = $.extend({\n\t\t\t\tcheckedClass: _checked,\n\t\t\t\tdisabledClass: _disabled,\n\t\t\t\tindeterminateClass: _indeterminate,\n\t\t\t\tlabelHover: true\n\t\t\t},\n\t\t\toptions),\n\n\t\t\tselector = settings.handle,\n\t\t\thoverClass = settings.hoverClass || 'hover',\n\t\t\tfocusClass = settings.focusClass || 'focus',\n\t\t\tactiveClass = settings.activeClass || 'active',\n\t\t\tlabelHover = !!settings.labelHover,\n\t\t\tlabelHoverClass = settings.labelHoverClass || 'hover',\n\n\t\t\t// Setup clickable area\n\t\t\tarea = ('' + settings.increaseArea).replace('%', '') | 0;\n\n\t\t\t// Selector limit\n\t\t\tif (selector == _checkbox || selector == _radio) {\n\t\t\t\thandle = 'input[type=\"' + selector + '\"]';\n\t\t\t}\n\n\t\t\t// Clickable area limit\n\t\t\tif (area < -50) {\n\t\t\t\tarea = -50;\n\t\t\t}\n\n\t\t\t// Walk around the selector\n\t\t\twalker(this);\n\n\t\t\treturn stack.each(function() {\n\t\t\t\tvar self = $(this);\n\n\t\t\t\t// If already customized\n\t\t\t\ttidy(self);\n\n\t\t\t\tvar node = this,\n\t\t\t\tid = node.id,\n\n\t\t\t\t// Layer styles\n\t\t\t\toffset = -area + '%',\n\t\t\t\tsize = 100 + (area * 2) + '%',\n\t\t\t\tlayer = {\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\ttop: offset,\n\t\t\t\t\tleft: offset,\n\t\t\t\t\tdisplay: 'block',\n\t\t\t\t\twidth: size,\n\t\t\t\t\theight: size,\n\t\t\t\t\tmargin: 0,\n\t\t\t\t\tpadding: 0,\n\t\t\t\t\tbackground: '#fff',\n\t\t\t\t\tborder: 0,\n\t\t\t\t\topacity: 0\n\t\t\t\t},\n\n\t\t\t\t// Choose how to hide input\n\t\t\t\thide = _mobile ? {\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t}: area ? layer: {\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\topacity: 0\n\t\t\t\t},\n\n\t\t\t\t// Get proper class\n\t\t\t\tclassName = node[_type] == _checkbox ? settings.checkboxClass || 'i' + _checkbox: settings.radioClass || 'i' + _radio,\n\n\t\t\t\t// Find assigned labels\n\t\t\t\tlabel = $(_label + '[for=\"' + id + '\"]').add(self.closest(_label)),\n\n\t\t\t\t// Check ARIA option\n\t\t\t\taria = !!settings.aria,\n\n\t\t\t\t// Set ARIA placeholder\n\t\t\t\tariaID = _iCheck + '-' + Math.random().toString(36).substr(2, 6),\n\n\t\t\t\t// Parent & helper\n\t\t\t\tparent = '<div class=\"' + className + '\" ' + (aria ? 'role=\"' + node[_type] + '\" ': ''),\n\t\t\t\thelper;\n\n\t\t\t\t// Set ARIA \"labelledby\"\n\t\t\t\tif (aria) {\n\t\t\t\t\tlabel.each(function() {\n\t\t\t\t\t\tparent += 'aria-labelledby=\"';\n\n\t\t\t\t\t\tif (this.id) {\n\t\t\t\t\t\t\tparent += this.id;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.id = ariaID;\n\t\t\t\t\t\t\tparent += ariaID;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tparent += '\"';\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Wrap input\n\t\t\t\tparent = self.wrap(parent + '/>')[_callback]('ifCreated').parent().append(settings.insert);\n\n\t\t\t\t// Layer addition\n\t\t\t\thelper = $('<ins class=\"' + _iCheckHelper + '\"/>').css(layer).appendTo(parent);\n\n\t\t\t\t// Finalize customization\n\t\t\t\tself.data(_iCheck, {\n\t\t\t\t\to: settings,\n\t\t\t\t\ts: self.attr('style')\n\t\t\t\t}).css(hide); !! settings.inheritClass && parent[_add](node.className || ''); !! settings.inheritID && id && parent.attr('id', _iCheck + '-' + id);\n\t\t\t\tparent.css('position') == 'static' && parent.css('position', 'relative');\n\t\t\t\toperate(self, true, _update);\n\n\t\t\t\t// Label events\n\t\t\t\tif (label.length) {\n\t\t\t\t\tlabel.on(_click + '.i mouseover.i mouseout.i ' + _touch,\n\t\t\t\t\tfunction(event) {\n\t\t\t\t\t\tvar type = event[_type],\n\t\t\t\t\t\titem = $(this);\n\n\t\t\t\t\t\t// Do nothing if input is disabled\n\t\t\t\t\t\tif (!node[_disabled]) {\n\n\t\t\t\t\t\t\t// Click\n\t\t\t\t\t\t\tif (type == _click) {\n\t\t\t\t\t\t\t\tif ($(event.target).is('a')) {\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\toperate(self, false, true);\n\n\t\t\t\t\t\t\t\t// Hover state\n\t\t\t\t\t\t\t} else if (labelHover) {\n\n\t\t\t\t\t\t\t\t// mouseout|touchend\n\t\t\t\t\t\t\t\tif (/ut|nd/.test(type)) {\n\t\t\t\t\t\t\t\t\tparent[_remove](hoverClass);\n\t\t\t\t\t\t\t\t\titem[_remove](labelHoverClass);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tparent[_add](hoverClass);\n\t\t\t\t\t\t\t\t\titem[_add](labelHoverClass);\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\tif (_mobile) {\n\t\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\treturn false;\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// Input events\n\t\t\t\tself.on(_click + '.i focus.i blur.i keyup.i keydown.i keypress.i',\n\t\t\t\tfunction(event) {\n\t\t\t\t\tvar type = event[_type],\n\t\t\t\t\tkey = event.keyCode;\n\n\t\t\t\t\t// Click\n\t\t\t\t\tif (type == _click) {\n\t\t\t\t\t\treturn false;\n\n\t\t\t\t\t\t// Keydown\n\t\t\t\t\t} else if (type == 'keydown' && key == 32) {\n\t\t\t\t\t\tif (! (node[_type] == _radio && node[_checked])) {\n\t\t\t\t\t\t\tif (node[_checked]) {\n\t\t\t\t\t\t\t\toff(self, _checked);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\ton(self, _checked);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn false;\n\n\t\t\t\t\t\t// Keyup\n\t\t\t\t\t} else if (type == 'keyup' && node[_type] == _radio) { ! node[_checked] && on(self, _checked);\n\n\t\t\t\t\t\t// Focus/blur\n\t\t\t\t\t} else if (/us|ur/.test(type)) {\n\t\t\t\t\t\tparent[type == 'blur' ? _remove: _add](focusClass);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t// Helper events\n\t\t\t\thelper.on(_click + ' mousedown mouseup mouseover mouseout ' + _touch,\n\t\t\t\tfunction(event) {\n\t\t\t\t\tvar type = event[_type],\n\n\t\t\t\t\t// mousedown|mouseup\n\t\t\t\t\ttoggle = /wn|up/.test(type) ? activeClass: hoverClass;\n\n\t\t\t\t\t// Do nothing if input is disabled\n\t\t\t\t\tif (!node[_disabled]) {\n\n\t\t\t\t\t\t// Click\n\t\t\t\t\t\tif (type == _click) {\n\t\t\t\t\t\t\toperate(self, false, true);\n\n\t\t\t\t\t\t\t// Active and hover states\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// State is on\n\t\t\t\t\t\t\tif (/wn|er|in/.test(type)) {\n\n\t\t\t\t\t\t\t\t// mousedown|mouseover|touchbegin\n\t\t\t\t\t\t\t\tparent[_add](toggle);\n\n\t\t\t\t\t\t\t\t// State is off\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tparent[_remove](toggle + ' ' + activeClass);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Label hover\n\t\t\t\t\t\t\tif (label.length && labelHover && toggle == hoverClass) {\n\n\t\t\t\t\t\t\t\t// mouseout|touchend\n\t\t\t\t\t\t\t\tlabel[/ut|nd/.test(type) ? _remove: _add](labelHoverClass);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (_mobile) {\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn false;\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\treturn this;\n\t\t}\n\t};\n\n\t// Do something with inputs\n\tfunction operate(input, direct, method) {\n\t\tvar node = input[0],\n\t\tstate = /er/.test(method) ? _indeterminate: /bl/.test(method) ? _disabled: _checked,\n\t\tactive = method == _update ? {\n\t\t\tchecked: node[_checked],\n\t\t\tdisabled: node[_disabled],\n\t\t\tindeterminate: input.attr(_indeterminate) == 'true' || input.attr(_determinate) == 'false'\n\t\t}: node[state];\n\n\t\t// Check, disable or indeterminate\n\t\tif (/^(ch|di|in)/.test(method) && !active) {\n\t\t\ton(input, state);\n\n\t\t\t// Uncheck, enable or determinate\n\t\t} else if (/^(un|en|de)/.test(method) && active) {\n\t\t\toff(input, state);\n\n\t\t\t// Update\n\t\t} else if (method == _update) {\n\n\t\t\t// Handle states\n\t\t\tfor (var each in active) {\n\t\t\t\tif (active[each]) {\n\t\t\t\t\ton(input, each, true);\n\t\t\t\t} else {\n\t\t\t\t\toff(input, each, true);\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if (!direct || method == 'toggle') {\n\n\t\t\t// Helper or label was clicked\n\t\t\tif (!direct) {\n\t\t\t\tinput[_callback]('ifClicked');\n\t\t\t}\n\n\t\t\t// Toggle checked state\n\t\t\tif (active) {\n\t\t\t\tif (node[_type] !== _radio) {\n\t\t\t\t\toff(input, state);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ton(input, state);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add checked, disabled or indeterminate state\n\tfunction on(input, state, keep) {\n\t\tvar node = input[0],\n\t\tparent = input.parent(),\n\t\tchecked = state == _checked,\n\t\tindeterminate = state == _indeterminate,\n\t\tdisabled = state == _disabled,\n\t\tcallback = indeterminate ? _determinate: checked ? _unchecked: 'enabled',\n\t\tregular = option(input, callback + capitalize(node[_type])),\n\t\tspecific = option(input, state + capitalize(node[_type]));\n\n\t\t// Prevent unnecessary actions\n\t\tif (node[state] !== true) {\n\n\t\t\t// Toggle assigned radio buttons\n\t\t\tif (!keep && state == _checked && node[_type] == _radio && node.name) {\n\t\t\t\tvar form = input.closest('form'),\n\t\t\t\tinputs = 'input[name=\"' + node.name + '\"]';\n\n\t\t\t\tinputs = form.length ? form.find(inputs) : $(inputs);\n\n\t\t\t\tinputs.each(function() {\n\t\t\t\t\tif (this !== node && $(this).data(_iCheck)) {\n\t\t\t\t\t\toff($(this), state);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Indeterminate state\n\t\t\tif (indeterminate) {\n\n\t\t\t\t// Add indeterminate state\n\t\t\t\tnode[state] = true;\n\n\t\t\t\t// Remove checked state\n\t\t\t\tif (node[_checked]) {\n\t\t\t\t\toff(input, _checked, 'force');\n\t\t\t\t}\n\n\t\t\t\t// Checked or disabled state\n\t\t\t} else {\n\n\t\t\t\t// Add checked or disabled state\n\t\t\t\tif (!keep) {\n\t\t\t\t\tnode[state] = true;\n\t\t\t\t}\n\n\t\t\t\t// Remove indeterminate state\n\t\t\t\tif (checked && node[_indeterminate]) {\n\t\t\t\t\toff(input, _indeterminate, false);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Trigger callbacks\n\t\t\tcallbacks(input, checked, state, keep);\n\t\t}\n\n\t\t// Add proper cursor\n\t\tif (node[_disabled] && !!option(input, _cursor, true)) {\n\t\t\tparent.find('.' + _iCheckHelper).css(_cursor, 'default');\n\t\t}\n\n\t\t// Add state class\n\t\tparent[_add](specific || option(input, state) || '');\n\n\t\t// Set ARIA attribute\n\t\tif ( !! parent.attr('role') && !indeterminate) {\n\t\t\tparent.attr('aria-' + (disabled ? _disabled: _checked), 'true');\n\t\t}\n\n\t\t// Remove regular state class\n\t\tparent[_remove](regular || option(input, callback) || '');\n\t}\n\n\t// Remove checked, disabled or indeterminate state\n\tfunction off(input, state, keep) {\n\t\tvar node = input[0],\n\t\tparent = input.parent(),\n\t\tchecked = state == _checked,\n\t\tindeterminate = state == _indeterminate,\n\t\tdisabled = state == _disabled,\n\t\tcallback = indeterminate ? _determinate: checked ? _unchecked: 'enabled',\n\t\tregular = option(input, callback + capitalize(node[_type])),\n\t\tspecific = option(input, state + capitalize(node[_type]));\n\n\t\t// Prevent unnecessary actions\n\t\tif (node[state] !== false) {\n\n\t\t\t// Toggle state\n\t\t\tif (indeterminate || !keep || keep == 'force') {\n\t\t\t\tnode[state] = false;\n\t\t\t}\n\n\t\t\t// Trigger callbacks\n\t\t\tcallbacks(input, checked, callback, keep);\n\t\t}\n\n\t\t// Add proper cursor\n\t\tif (!node[_disabled] && !!option(input, _cursor, true)) {\n\t\t\tparent.find('.' + _iCheckHelper).css(_cursor, 'pointer');\n\t\t}\n\n\t\t// Remove state class\n\t\tparent[_remove](specific || option(input, state) || '');\n\n\t\t// Set ARIA attribute\n\t\tif ( !! parent.attr('role') && !indeterminate) {\n\t\t\tparent.attr('aria-' + (disabled ? _disabled: _checked), 'false');\n\t\t}\n\n\t\t// Add regular state class\n\t\tparent[_add](regular || option(input, callback) || '');\n\t}\n\n\t// Remove all traces\n\tfunction tidy(input, callback) {\n\t\tif (input.data(_iCheck)) {\n\n\t\t\t// Remove everything except input\n\t\t\tinput.parent().html(input.attr('style', input.data(_iCheck).s || ''));\n\n\t\t\t// Callback\n\t\t\tif (callback) {\n\t\t\t\tinput[_callback](callback);\n\t\t\t}\n\n\t\t\t// Unbind events\n\t\t\tinput.off('.i').unwrap();\n\t\t\t$(_label + '[for=\"' + input[0].id + '\"]').add(input.closest(_label)).off('.i');\n\t\t}\n\t}\n\n\t// Get some option\n\tfunction option(input, state, regular) {\n\t\tif (input.data(_iCheck)) {\n\t\t\treturn input.data(_iCheck).o[state + (regular ? '': 'Class')];\n\t\t}\n\t}\n\n\t// Capitalize some string\n\tfunction capitalize(string) {\n\t\treturn string.charAt(0).toUpperCase() + string.slice(1);\n\t}\n\n\t// Executable handlers\n\tfunction callbacks(input, checked, callback, keep) {\n\t\tif (!keep) {\n\t\t\tif (checked) {\n\t\t\t\tinput[_callback]('ifToggled');\n\t\t\t}\n\n\t\t\tinput[_callback]('ifChanged')[_callback]('if' + capitalize(callback));\n\t\t}\n\t}\n})(window.jQuery || window.Zepto);\n\n/* =======================================================================\n * jQuery.raty.js v2.4.5- A Star Rating Plugin\n * -------------------------------------------------------------------\n * jQuery Raty is a plugin that generates a customizable star rating.\n * Licensed under The MIT License\n *\n * @version        2.4.5\n * @since          2010.06.11\n * @author         Washington Botelho\n * @documentation  wbotelhos.com/raty\n * @twitter        twitter.com/wbotelhos\n *\n * Usage:\n * -------------------------------------------------------------------\n * $('#star').raty();\n * <div id=\"star\"></div>\n * ======================================================================== */\n!(function($) {\n\tvar methods = {\n\t\tinit: function(settings) {\n\t\t\treturn this.each(function() {\n\t\t\t\tvar self = this,\n\t\t\t\t$this = $(self).empty();\n\t\t\t\tself.opt = $.extend(true, {},\n\t\t\t\t$.fn.raty.defaults, settings);\n\t\t\t\t$this.data('settings', self.opt);\n\t\t\t\tself.opt.number = methods.between(self.opt.number, 0, 20);\n\t\t\t\tif (self.opt.path.substring(self.opt.path.length - 1, self.opt.path.length) != '/') {\n\t\t\t\t\tself.opt.path += '/';\n\t\t\t\t}\n\t\t\t\tif (typeof self.opt.score == 'function') {\n\t\t\t\t\tself.opt.score = self.opt.score.call(self);\n\t\t\t\t}\n\t\t\t\tif (self.opt.score) {\n\t\t\t\t\tself.opt.score = methods.between(self.opt.score, 0, self.opt.number);\n\t\t\t\t}\n\t\t\t\tfor (var i = 1; i <= self.opt.number; i++) {\n\t\t\t\t\t$('<img />', {\n\t\t\t\t\t\tsrc: self.opt.path + ((!self.opt.score || self.opt.score < i) ? self.opt.starOff: self.opt.starOn),\n\t\t\t\t\t\talt: i,\n\t\t\t\t\t\ttitle: (i <= self.opt.hints.length && self.opt.hints[i - 1] !== null) ? self.opt.hints[i - 1] : i\n\t\t\t\t\t}).appendTo(self);\n\n\t\t\t\t\tif (self.opt.space) {\n\t\t\t\t\t\t$this.append((i < self.opt.number) ? '': '');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tself.stars = $this.children('img:not(\".raty-cancel\")');\n\t\t\t\tself.score = $('<input />', {\n\t\t\t\t\ttype: 'hidden',\n\t\t\t\t\tname: self.opt.scoreName\n\t\t\t\t}).appendTo(self);\n\t\t\t\tif (self.opt.score && self.opt.score > 0) {\n\t\t\t\t\tself.score.val(self.opt.score);\n\t\t\t\t\tmethods.roundStar.call(self, self.opt.score);\n\t\t\t\t}\n\t\t\t\tif (self.opt.iconRange) {\n\t\t\t\t\tmethods.fill.call(self, self.opt.score);\t\t\t\t}\n\t\t\t\tmethods.setTarget.call(self, self.opt.score, self.opt.targetKeep);\n\t\t\t\tvar space = self.opt.space ? 4 : 0,\n\t\t\t\twidth = self.opt.width || (self.opt.number * self.opt.size + self.opt.number * space);\n\t\t\t\tif (self.opt.cancel) {\n\t\t\t\t\tself.cancel = $('<img />', {\n\t\t\t\t\t\tsrc: self.opt.path + self.opt.cancelOff,\n\t\t\t\t\t\talt: 'x',\n\t\t\t\t\t\ttitle: self.opt.cancelHint,\n\t\t\t\t\t\t'class': 'raty-cancel'\n\t\t\t\t\t});\n\t\t\t\t\tif (self.opt.cancelPlace == 'left') {\n\t\t\t\t\t\t//$this.prepend('&#160;').prepend(self.cancel);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t//$this.append('&#160;').append(self.cancel);\n\t\t\t\t\t}\n\t\t\t\t\twidth += (self.opt.size + space);\n\t\t\t\t}\n\t\t\t\tif (self.opt.readOnly) {\n\t\t\t\t\tmethods.fixHint.call(self);\n\n\t\t\t\t\tif (self.cancel) {\n\t\t\t\t\t\tself.cancel.hide();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t$this.css('cursor', 'pointer');\n\t\t\t\t\tmethods.bindAction.call(self);\n\t\t\t\t}\n\t\t\t\t//$this.css('width', width);\n\t\t\t});\n\t\t},\n\t\tbetween: function(value, min, max) {\n\t\t\treturn Math.min(Math.max(parseFloat(value), min), max);\n\t\t},\n\t\tbindAction: function() {\n\t\t\tvar self = this,\n\t\t\t$this = $(self);\n\t\t\t$this.mouseleave(function() {\n\t\t\t\tvar score = self.score.val() || undefined;\n\n\t\t\t\tmethods.initialize.call(self, score);\n\t\t\t\tmethods.setTarget.call(self, score, self.opt.targetKeep);\n\n\t\t\t\tif (self.opt.mouseover) {\n\t\t\t\t\tself.opt.mouseover.call(self, score);\n\t\t\t\t}\n\t\t\t});\n\t\t\tvar action = self.opt.half ? 'mousemove': 'mouseover';\n\t\t\tif (self.opt.cancel) {\n\t\t\t\tself.cancel.mouseenter(function() {\n\t\t\t\t\t$(this).attr('src', self.opt.path + self.opt.cancelOn);\n\n\t\t\t\t\tself.stars.attr('src', self.opt.path + self.opt.starOff);\n\n\t\t\t\t\tmethods.setTarget.call(self, null, true);\n\n\t\t\t\t\tif (self.opt.mouseover) {\n\t\t\t\t\t\tself.opt.mouseover.call(self, null);\n\t\t\t\t\t}\n\t\t\t\t}).mouseleave(function() {\n\t\t\t\t\t$(this).attr('src', self.opt.path + self.opt.cancelOff);\n\n\t\t\t\t\tif (self.opt.mouseover) {\n\t\t\t\t\t\tself.opt.mouseover.call(self, self.score.val() || null);\n\t\t\t\t\t}\n\t\t\t\t}).click(function(evt) {\n\t\t\t\t\tself.score.removeAttr('value');\n\t\t\t\t\tif (self.opt.click) {\n\t\t\t\t\t\tself.opt.click.call(self, null, evt);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tself.stars.bind(action,\n\t\t\tfunction(evt) {\n\t\t\t\tvar value = parseInt(this.alt, 10);\n\t\t\t\tif (self.opt.half) {\n\t\t\t\t\tvar position = parseFloat((evt.pageX - $(this).offset().left) / self.opt.size),\n\t\t\t\t\tdiff = (position > .5) ? 1 : .5;\n\t\t\t\t\tvalue = parseFloat(this.alt) - 1 + diff;\n\t\t\t\t\tmethods.fill.call(self, value);\n\t\t\t\t\tif (self.opt.precision) {\n\t\t\t\t\t\tvalue = value - diff + position;\n\t\t\t\t\t}\n\t\t\t\t\tmethods.showHalf.call(self, value);\n\t\t\t\t} else {\n\t\t\t\t\tmethods.fill.call(self, value);\n\t\t\t\t}\n\t\t\t\t$this.data('score', value);\n\t\t\t\tmethods.setTarget.call(self, value, true);\n\t\t\t\tif (self.opt.mouseover) {\n\t\t\t\t\tself.opt.mouseover.call(self, value, evt);\n\t\t\t\t}\n\t\t\t}).click(function(evt) {\n\t\t\t\tself.score.val((self.opt.half || self.opt.precision) ? $this.data('score') : this.alt);\n\t\t\t\tif (self.opt.click) {\n\t\t\t\t\tself.opt.click.call(self, self.score.val(), evt);\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tcancel: function(isClick) {\n\t\t\treturn $(this).each(function() {\n\t\t\t\tvar self = this,\n\t\t\t\t$this = $(self);\n\n\t\t\t\tif ($this.data('readonly') === true) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t\tif (isClick) {\n\t\t\t\t\tmethods.click.call(self, null);\n\t\t\t\t} else {\n\t\t\t\t\tmethods.score.call(self, null);\n\t\t\t\t}\n\n\t\t\t\tself.score.removeAttr('value');\n\t\t\t});\n\t\t},\n\t\tclick: function(score) {\n\t\t\treturn $(this).each(function() {\n\t\t\t\tif ($(this).data('readonly') === true) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t\tmethods.initialize.call(this, score);\n\n\t\t\t\tif (this.opt.click) {\n\t\t\t\t\tthis.opt.click.call(this, score);\n\t\t\t\t} else {\n\t\t\t\t\tmethods.error.call(this, 'you must add the \"click: function(score, evt) { }\" callback.');\n\t\t\t\t}\n\t\t\t\tmethods.setTarget.call(this, score, true);\n\t\t\t});\n\t\t},\n\t\terror: function(message) {\n\t\t\t$(this).html(message);\n\t\t\t$.error(message);\n\t\t},\n\t\tfill: function(score) {\n\t\t\tvar self = this,\n\t\t\tnumber = self.stars.length,\n\t\t\tcount = 0,\n\t\t\t$star, star, icon;\n\t\t\tfor (var i = 1; i <= number; i++) {\n\t\t\t\t$star = self.stars.eq(i - 1);\n\t\t\t\tif (self.opt.iconRange && self.opt.iconRange.length > count) {\n\t\t\t\t\tstar = self.opt.iconRange[count];\n\t\t\t\t\tif (self.opt.single) {\n\t\t\t\t\t\ticon = (i == score) ? (star.on || self.opt.starOn) : (star.off || self.opt.starOff);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ticon = (i <= score) ? (star.on || self.opt.starOn) : (star.off || self.opt.starOff);\n\t\t\t\t\t}\n\t\t\t\t\tif (i <= star.range) {\n\t\t\t\t\t\t$star.attr('src', self.opt.path + icon);\n\t\t\t\t\t}\n\t\t\t\t\tif (i == star.range) {\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (self.opt.single) {\n\t\t\t\t\t\ticon = (i == score) ? self.opt.starOn: self.opt.starOff;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ticon = (i <= score) ? self.opt.starOn: self.opt.starOff;\n\t\t\t\t\t}\n\t\t\t\t\t$star.attr('src', self.opt.path + icon);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tfixHint: function() {\n\t\t\tvar $this = $(this),\n\t\t\tscore = parseInt(this.score.val(), 10),\n\t\t\thint = this.opt.noRatedMsg;\n\n\t\t\tif (!isNaN(score) && score > 0) {\n\t\t\t\thint = (score <= this.opt.hints.length && this.opt.hints[score - 1] !== null) ? this.opt.hints[score - 1] : score;\n\t\t\t}\n\t\t\t$this.data('readonly', true).css('cursor', 'default').attr('title', hint);\n\t\t\tthis.score.attr('readonly', 'readonly');\n\t\t\tthis.stars.attr('title', hint);\n\t\t},\n\t\tgetScore: function() {\n\t\t\tvar score = [],\n\t\t\tvalue;\n\t\t\t$(this).each(function() {\n\t\t\t\tvalue = this.score.val();\n\t\t\t\tscore.push(value ? parseFloat(value) : undefined);\n\t\t\t});\n\t\t\treturn (score.length > 1) ? score: score[0];\n\t\t},\n\t\treadOnly: function(isReadOnly) {\n\t\t\treturn this.each(function() {\n\t\t\t\tvar $this = $(this);\n\t\t\t\tif ($this.data('readonly') === isReadOnly) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tif (this.cancel) {\n\t\t\t\t\tif (isReadOnly) {\n\t\t\t\t\t\tthis.cancel.hide();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.cancel.show();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (isReadOnly) {\n\t\t\t\t\t$this.unbind();\n\t\t\t\t\t$this.children('img').unbind();\n\t\t\t\t\tmethods.fixHint.call(this);\n\t\t\t\t} else {\n\t\t\t\t\tmethods.bindAction.call(this);\n\t\t\t\t\tmethods.unfixHint.call(this);\n\t\t\t\t}\n\n\t\t\t\t$this.data('readonly', isReadOnly);\n\t\t\t});\n\t\t},\n\t\treload: function() {\n\t\t\treturn methods.set.call(this, {});\n\t\t},\n\t\troundStar: function(score) {\n\t\t\tvar diff = (score - Math.floor(score)).toFixed(2);\n\n\t\t\tif (diff > this.opt.round.down) {\n\t\t\t\tvar icon = this.opt.starOn; // Full up: [x.76 .. x.99]\n\t\t\t\tif (diff < this.opt.round.up && this.opt.halfShow) { // Half: [x.26 .. x.75]\n\t\t\t\t\ticon = this.opt.starHalf;\n\t\t\t\t} else if (diff < this.opt.round.full) { // Full down: [x.00 .. x.5]\n\t\t\t\t\ticon = this.opt.starOff;\n\t\t\t\t}\n\n\t\t\t\tthis.stars.eq(Math.ceil(score) - 1).attr('src', this.opt.path + icon);\n\t\t\t} // Full down: [x.00 .. x.25]\n\t\t},\n\t\tscore: function() {\n\t\t\treturn arguments.length ? methods.setScore.apply(this, arguments) : methods.getScore.call(this);\n\t\t},\n\t\tset: function(settings) {\n\t\t\tthis.each(function() {\n\t\t\t\tvar $this = $(this),\n\t\t\t\tactual = $this.data('settings'),\n\t\t\t\tclone = $this.clone().removeAttr('style').insertBefore($this);\n\n\t\t\t\t$this.remove();\n\n\t\t\t\tclone.raty($.extend(actual, settings));\n\t\t\t});\n\n\t\t\treturn $(this.selector);\n\t\t},\n\t\tsetScore: function(score) {\n\t\t\treturn $(this).each(function() {\n\t\t\t\tif ($(this).data('readonly') === true) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t\tmethods.initialize.call(this, score);\n\t\t\t\tmethods.setTarget.call(this, score, true);\n\t\t\t});\n\t\t},\n\t\tsetTarget: function(value, isKeep) {\n\t\t\tif (this.opt.target) {\n\t\t\t\tvar $target = $(this.opt.target);\n\n\t\t\t\tif ($target.length == 0) {\n\t\t\t\t\tmethods.error.call(this, '目标选择器无效或丢失!');\n\t\t\t\t}\n\n\t\t\t\tvar score = value;\n\n\t\t\t\tif (!isKeep || score === undefined) {\n\t\t\t\t\tscore = this.opt.targetText;\n\t\t\t\t} else {\n\t\t\t\t\tif (this.opt.targetType == 'hint') {\n\t\t\t\t\t\tscore = (score === null && this.opt.cancel) ? this.opt.cancelHint: this.opt.hints[Math.ceil(score - 1)];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tscore = this.opt.precision ? parseFloat(score).toFixed(1) : parseInt(score, 10);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (this.opt.targetFormat.indexOf('{score}') < 0) {\n\t\t\t\t\tmethods.error.call(this, '模版 \"{score}\" 找不到!');\n\t\t\t\t}\n\n\t\t\t\tif (value !== null) {\n\t\t\t\t\tscore = this.opt.targetFormat.toString().replace('{score}', score);\n\t\t\t\t}\n\n\t\t\t\tif ($target.is(':input')) {\n\t\t\t\t\t$target.val(score);\n\t\t\t\t} else {\n\t\t\t\t\t$target.html(score);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tshowHalf: function(score) {\n\t\t\tvar diff = (score - Math.floor(score)).toFixed(1);\n\n\t\t\tif (diff > 0 && diff < .6) {\n\t\t\t\tthis.stars.eq(Math.ceil(score) - 1).attr('src', this.opt.path + this.opt.starHalf);\n\t\t\t}\n\t\t},\n\t\tinitialize: function(score) {\n\t\t\tscore = !score ? 0 : methods.between(score, 0, this.opt.number);\n\n\t\t\tmethods.fill.call(this, score);\n\n\t\t\tif (score > 0) {\n\t\t\t\tif (this.opt.halfShow) {\n\t\t\t\t\tmethods.roundStar.call(this, score);\n\t\t\t\t}\n\n\t\t\t\tthis.score.val(score);\n\t\t\t}\n\t\t},\n\t\tunfixHint: function() {\n\t\t\tfor (var i = 0; i < this.opt.number; i++) {\n\t\t\t\tthis.stars.eq(i).attr('title', (i < this.opt.hints.length && this.opt.hints[i] !== null) ? this.opt.hints[i] : i);\n\t\t\t}\n\n\t\t\t$(this).data('readonly', false).css('cursor', 'pointer').removeAttr('title');\n\n\t\t\tthis.score.attr('readonly', 'readonly');\n\t\t}\n\t};\n\n\t$.fn.raty = function(method) {\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 + ' 不存在!');\n\t\t}\n\t};\n\n\t$.fn.raty.defaults = {\n\t\tcancel: false,\n\t\tcancelHint: '取消评级!',\n\t\tcancelOff: 'cancel-off.png',\n\t\tcancelOn: 'cancel-on.png',\n\t\tcancelPlace: 'left',\n\t\tclick: undefined,\n\t\thalf: false,\n\t\thalfShow: true,\n\t\thints: ['10', '20', '30', '40', '50', '60', '70', '80', '90', '100'],\n\t\ticonRange: undefined,\n\t\tmouseover: undefined,\n\t\tnoRatedMsg: '没有额定',\n\t\tnumber: 10,\n\t\tpath: 'images/',\n\t\tprecision: false,\n\t\tround: {\n\t\t\tdown: .25,\n\t\t\tfull: .6,\n\t\t\tup: .76\n\t\t},\n\t\treadOnly: false,\n\t\tscore: undefined,\n\t\tscoreName: 'score',\n\t\tsingle: false,\n\t\tsize: 16,\n\t\tspace: true,\n\t\tstarHalf: 'star-half.png',\n\t\tstarOff: 'star-off.png',\n\t\tstarOn: 'star-on.png',\n\t\ttarget: undefined,\n\t\ttargetFormat: '{score}',\n\t\ttargetKeep: false,\n\t\ttargetText: '',\n\t\ttargetType: 'hint',\n\t\twidth: undefined\n\t};\n})(jQuery);\n\n/* =======================================================================\n * jQuery.onePageNav.js v0.9One Page Nav Plugin\n * http://github.com/davist11/jQuery-One-Page-Nav\n * Copyright (c) 2010 Trevor Davis (http://trevordavis.net)\n * Dual licensed under the MIT and GPL licenses.\n * Uses the same license as jQuery, see:\n * http://jquery.org/license\n * Example usage:\n * $('#nav').onePageNav({\n *   currentClass: 'current',\n *   changeHash: false,\n *   scrollSpeed: 750\n * });\n * ========================================================================*/\n!(function($) {\n\t$.fn.onePageNav = function(options) {\n\t\tvar opts = $.extend({},\n\t\t$.fn.onePageNav.defaults, options),\n\t\tonePageNav = {};\n\n\t\tonePageNav.sections = {};\n\n\t\tonePageNav.bindNav = function($el, $this, o) {\n\t\t\tvar $par = $el.parent(),\n\t\t\tnewLoc = $el.attr('href'),\n\t\t\t$win = $(window);\n\n\t\t\tif (!$par.hasClass(o.currentClass)) {\n\t\t\t\tif (o.begin) {\n\t\t\t\t\to.begin();\n\t\t\t\t}\n\t\t\t\tonePageNav.adjustNav($this, $par, o.currentClass);\n\t\t\t\t$win.unbind('.onePageNav');\n\t\t\t\t$.scrollTo(newLoc, o.scrollSpeed, {\n\t\t\t\t\teasing: o.easing,\n\t\t\t\t\toffset: {\n\t\t\t\t\t\ttop: -o.scrollOffset\n\t\t\t\t\t},\n\t\t\t\t\tonAfter: function() {\n\t\t\t\t\t\tif (o.changeHash) {\n\t\t\t\t\t\t\twindow.location.hash = newLoc;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$win.bind('scroll.onePageNav',\n\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\tonePageNav.scrollChange($this, o);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (o.end) {\n\t\t\t\t\t\t\to.end();\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\tonePageNav.adjustNav = function($this, $el, curClass) {\n\t\t\t$this.find('.' + curClass).removeClass(curClass);\n\t\t\t$el.addClass(curClass);\n\t\t};\n\n\t\tonePageNav.getPositions = function($this, o) {\n\t\t\tvar $nav = $this.find('a');\n\n\t\t\tif (o.filter !== '') {\n\t\t\t\t$nav = $nav.filter(o.filter);\n\t\t\t}\n\n\t\t\t$nav.each(function() {\n\t\t\t\tvar linkHref = $(this).attr('href'),\n\t\t\t\tdivPos = $(linkHref).offset(),\n\t\t\t\ttopPos = divPos.top;\n\n\t\t\t\tonePageNav.sections[linkHref.substr(1)] = Math.round(topPos) - o.scrollOffset;\n\t\t\t});\n\t\t};\n\n\t\tonePageNav.getSection = function(windowPos, o) {\n\t\t\tvar returnValue = '',\n\t\t\twindowHeight = Math.round($(window).height() * o.scrollThreshold);\n\n\t\t\tfor (var section in onePageNav.sections) {\n\t\t\t\tif ((onePageNav.sections[section] - windowHeight) < windowPos) {\n\t\t\t\t\treturnValue = section;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn returnValue;\n\t\t};\n\n\t\tonePageNav.scrollChange = function($this, o) {\n\t\t\tonePageNav.getPositions($this, o);\n\n\t\t\tvar windowTop = $(window).scrollTop(),\n\t\t\tposition = onePageNav.getSection(windowTop, o);\n\n\t\t\tif (position !== '') {\n\t\t\t\tonePageNav.adjustNav($this, $this.find('a[href=#' + position + ']').parent(), o.currentClass);\n\t\t\t}\n\t\t};\n\n\t\tonePageNav.init = function($this, o) {\n\t\t\tvar didScroll = false,\n\t\t\t$nav = $this.find('a');\n\n\t\t\tif (o.filter !== '') {\n\t\t\t\t$nav = $nav.filter(o.filter);\n\t\t\t}\n\n\t\t\t$nav.bind('click',\n\t\t\tfunction(e) {\n\t\t\t\tonePageNav.bindNav($(this), $this, o);\n\t\t\t\te.preventDefault();\n\t\t\t});\n\n\t\t\tonePageNav.getPositions($this, o);\n\n\t\t\t$(window).bind('scroll.onePageNav',\n\t\t\tfunction() {\n\t\t\t\tdidScroll = true;\n\t\t\t});\n\n\t\t\tsetInterval(function() {\n\t\t\t\tif (didScroll) {\n\t\t\t\t\tdidScroll = false;\n\t\t\t\t\tonePageNav.scrollChange($this, o);\n\t\t\t\t}\n\t\t\t},\n\t\t\t250);\n\t\t};\n\n\t\treturn this.each(function() {\n\t\t\tvar $this = $(this),\n\t\t\to = $.meta ? $.extend({},\n\t\t\topts, $this.data()) : opts;\n\n\t\t\tonePageNav.init($this, o);\n\n\t\t});\n\t};\n\n\t// default options\n\t$.fn.onePageNav.defaults = {\n\t\tcurrentClass: 'current',\n\t\tchangeHash: false,\n\t\teasing: 'swing',\n\t\tfilter: '',\n\t\tscrollSpeed: 750,\n\t\tscrollOffset: 0,\n\t\tscrollThreshold: 0.5,\n\t\tbegin: false,\n\t\tend: false\n\t};\n})(jQuery);\n\n /* =======================================================================\n * jQuery.ColorPicker.js 颜色控件\n * ========================================================================*/\n(function($) {\n\t'use strict';\n\tvar name = 'Hui.colorPicker'; // modal name\n\tvar TEAMPLATE = '<div class=\"colorpicker\"><button type=\"button\" class=\"btn dropdown-toggle\" data-toggle=\"dropdown\"><span class=\"cp-title\"></span><i class=\"ic\"></i></button><ul class=\"dropdown-menu clearfix\"></ul></div>';\n\tvar LANG = {\n\t\tzh_cn: {\n\t\t\terrorTip: \"不是有效的颜色值\"\n\t\t},\n\t\tzh_tw: {\n\t\t\terrorTip: \"不是有效的顏色值\"\n\t\t},\n\t\ten: {\n\t\t\terrorTip: \"Not a valid color value\"\n\t\t}\n\t};\n\n\t// The ColorPicker modal class\n\tvar ColorPicker = function(element, options) {\n\t\tthis.name = name;\n\t\tthis.$ = $(element);\n\n\t\tthis.getOptions(options);\n\t\tthis.init();\n\t};\n\n\t// default options\n\tColorPicker.DEFAULTS = {\n\t\tcolors: ['#00BCD4', '#388E3C', '#3280fc', '#3F51B5', '#9C27B0', '#795548', '#F57C00', '#F44336', '#E91E63'],\n\t\tpullMenuRight: true,\n\t\twrapper: 'btn-wrapper',\n\t\ttileSize: 30,\n\t\tlineCount: 5,\n\t\toptional: true,\n\t\ttooltip: 'top',\n\t\ticon: 'caret-down',\n\t\t// btnTip: 'Tool tip in button'\n\t};\n\n\tColorPicker.prototype.init = function() {\n\t\tvar options = this.options,\n\t\tthat = this;\n\n\t\tthis.$picker = $(TEAMPLATE).addClass(options.wrapper);\n\t\tthis.$picker.find('.cp-title').toggle(options.title !== undefined).text(options.title);\n\t\tthis.$menu = this.$picker.find('.dropdown-menu').toggleClass('pull-right', options.pullMenuRight);\n\t\tthis.$btn = this.$picker.find('.btn.dropdown-toggle');\n\t\tthis.$btn.find('.ic').addClass('icon-' + options.icon);\n\t\tif (options.btnTip) {\n\t\t\tthis.$picker.attr('data-toggle', 'tooltip').tooltip({\n\t\t\t\ttitle: options.btnTip,\n\t\t\t\tplacement: options.tooltip,\n\t\t\t\tcontainer: 'body'\n\t\t\t});\n\t\t}\n\t\tthis.$.attr('data-provide', null).after(this.$picker);\n\n\t\t// init colors\n\t\tthis.colors = {};\n\t\t$.each(this.options.colors,\n\t\tfunction(idx, rawColor) {\n\t\t\tif ($.zui.Color.isColor(rawColor)) {\n\t\t\t\tvar color = new $.zui.Color(rawColor);\n\t\t\t\tthat.colors[color.toCssStr()] = color;\n\t\t\t}\n\t\t});\n\n\t\tthis.updateColors();\n\t\tvar that = this;\n\t\tthis.$picker.on('click', '.cp-tile',\n\t\tfunction() {\n\t\t\tthat.setValue($(this).data('color'));\n\t\t});\n\t\tvar $input = this.$;\n\t\tvar setInputColor = function() {\n\t\t\tvar val = $input.val();\n\t\t\tvar isColor = $.zui.Color.isColor(val);\n\t\t\t$input.parent().toggleClass('has-error', !isColor && !(options.optional && val === ''));\n\t\t\tif (isColor) {\n\t\t\t\tthat.setValue(val, true);\n\t\t\t} else {\n\t\t\t\tif (options.optional && val === '') {\n\t\t\t\t\t$input.tooltip('hide');\n\t\t\t\t} else if (!$input.is(':focus')) {\n\t\t\t\t\t$input.tooltip('show', options.errorTip);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif ($input.is('input:not([type=hidden])')) {\n\t\t\tif (options.tooltip) {\n\t\t\t\t$input.attr('data-toggle', 'tooltip').tooltip({\n\t\t\t\t\ttrigger: 'manual',\n\t\t\t\t\tplacement: options.tooltip,\n\t\t\t\t\ttipClass: 'tooltip-danger',\n\t\t\t\t\tcontainer: 'body'\n\t\t\t\t});\n\t\t\t}\n\t\t\t$input.on('keyup paste input change', setInputColor);\n\t\t} else {\n\t\t\t$input.appendTo(this.$picker);\n\t\t}\n\t\tsetInputColor();\n\t};\n\n\tColorPicker.prototype.addColor = function(color) {\n\t\tvar hex = color.toCssStr(),\n\t\toptions = this.options;\n\n\t\tif (!this.colors[hex]) {\n\t\t\tthis.colors[hex] = color;\n\t\t}\n\n\t\tvar $a = $('<a href=\"###\" class=\"cp-tile\"></a>', {\n\t\t\ttitile: color\n\t\t}).data('color', color).css({\n\t\t\t'color': color.contrast().toCssStr(),\n\t\t\t'background': hex,\n\t\t\t'border-color': color.luma() > 0.43 ? '#ccc': 'transparent'\n\t\t}).attr('data-color', hex);\n\t\tthis.$menu.append($('<li/>').css({\n\t\t\twidth: options.tileSize,\n\t\t\theight: options.tileSize\n\t\t}).append($a));\n\t\tif (options.optional) {\n\t\t\tthis.$menu.find('.cp-tile.empty').parent().detach().appendTo(this.$menu);\n\t\t}\n\t};\n\n\tColorPicker.prototype.updateColors = function(colors) {\n\t\tvar $picker = this.$picker,\n\t\t$menu = this.$menu.empty(),\n\t\toptions = this.options,\n\t\tcolors = colors || this.colors,\n\t\tthat = this;\n\t\tvar bestLineCount = 0;\n\t\t$.each(colors,\n\t\tfunction(idx, color) {\n\t\t\tthat.addColor(color);\n\t\t\tbestLineCount++;\n\t\t});\n\t\tif (options.optional) {\n\t\t\tvar $li = $('<li><a class=\"cp-tile empty\" href=\"###\"></a></li>').css({\n\t\t\t\twidth: options.tileSize,\n\t\t\t\theight: options.tileSize\n\t\t\t});\n\t\t\tthis.$menu.append($li);\n\t\t\tbestLineCount++;\n\t\t}\n\t\t$menu.css('width', Math.min(bestLineCount, options.lineCount) * options.tileSize + 6);\n\t};\n\n\tColorPicker.prototype.setValue = function(color, notSetInput) {\n\t\tvar options = this.options;\n\t\tthis.$menu.find('.cp-tile.active').removeClass('active');\n\t\tvar hex = '';\n\t\tif (color) {\n\t\t\tvar c = new $.zui.Color(color);\n\t\t\thex = c.toCssStr().toLowerCase();\n\t\t\tthis.$btn.css({\n\t\t\t\tbackground: hex,\n\t\t\t\tcolor: c.contrast().toCssStr(),\n\t\t\t\tborderColor: c.luma() > 0.43 ? '#ccc': hex\n\t\t\t});\n\t\t\tif (!this.colors[hex]) {\n\t\t\t\tthis.addColor(c);\n\t\t\t}\n\t\t\tif (!notSetInput && this.$.val().toLowerCase() !== hex) {\n\t\t\t\tthis.$.val(hex).trigger('change');\n\t\t\t}\n\t\t\tthis.$menu.find('.cp-tile[data-color=' + hex + ']').addClass('active');\n\t\t\tthis.$.tooltip('hide');\n\t\t\tthis.$.trigger('colorchange', c);\n\t\t} else {\n\t\t\tthis.$btn.attr('style', null);\n\t\t\tif (!notSetInput && this.$.val() !== '') {\n\t\t\t\tthis.$.val(hex).trigger('change');\n\t\t\t}\n\t\t\tif (options.optional) {\n\t\t\t\tthis.$.tooltip('hide');\n\t\t\t}\n\t\t\tthis.$menu.find('.cp-tile.empty').addClass('active');\n\t\t\tthis.$.trigger('colorchange', null);\n\t\t}\n\n\t\tif (options.updateBorder) {\n\t\t\t$(options.updateBorder).css('border-color', hex);\n\t\t}\n\t\tif (options.updateBackground) {\n\t\t\t$(options.updateBackground).css('background-color', hex);\n\t\t}\n\t\tif (options.updateColor) {\n\t\t\t$(options.updateText).css('color', hex);\n\t\t}\n\t\tif (options.updateText) {\n\t\t\t$(options.updateText).text(hex);\n\t\t}\n\t};\n\n\t// Get and init options\n\tColorPicker.prototype.getOptions = function(options) {\n\t\tvar thisOptions = $.extend({},\n\t\tColorPicker.DEFAULTS, this.$.data(), options);\n\t\tif (typeof thisOptions.colors === 'string') thisOptions.colors = thisOptions.colors.split(',');\n\t\tvar lang = (thisOptions.lang || $.zui.clientLang()).toLowerCase();\n\t\tif (!thisOptions.errorTip) {\n\t\t\tthisOptions.errorTip = LANG[lang].errorTip;\n\t\t}\n\t\tif (!$.fn.tooltip) thisOptions.btnTip = false;\n\t\tthis.options = thisOptions;\n\t};\n\n\t// Extense jquery element\n\t$.fn.colorPicker = function(option) {\n\t\treturn this.each(function() {\n\t\t\tvar $this = $(this);\n\t\t\tvar data = $this.data(name);\n\t\t\tvar options = typeof option == 'object' && option;\n\n\t\t\tif (!data) $this.data(name, (data = new ColorPicker(this, options)));\n\n\t\t\tif (typeof option == 'string') data[option]();\n\t\t});\n\t};\n\n\t$.fn.colorPicker.Constructor = ColorPicker;\n\n\t// Auto call colorPicker after document load complete\n\t$(function() {\n\t\t$('[data-provide=\"colorpicker\"]').colorPicker();\n\t});\n}(jQuery));\n\n/* =======================================================================\n * jquery.HuiaddFavorite.js 添加收藏\n * <a title=\"收藏本站\" href=\"javascript:;\" onClick=\"addFavoritepage('H-ui前端框架','http://www.h-ui.net/');\">收藏本站</a>\n * function shoucang(name,site){\n\t$.addFavorite({\n\t\tname:name,\n\t\tsite:site,\n\t});\n * ========================================================================*/\nfunction HuiaddFavorite(obj) {\n\tobj.site = obj.site || window.location.href;\n\tobj.name = obj.name || document.title;\n\ttry {\n\t\twindow.external.addFavorite(obj.site, obj.name);\n\t} catch(e) {\n\t\ttry {\n\t\t\twindow.sidebar.addPanel(name, site, \"\");\n\t\t} catch(e) {\n\t\t\t$.Huimodalalert(\"加入收藏失败，请使用Ctrl+D进行添加\", 2000);\n\t\t}\n\t}\n}\n\n/* ========================================================================\n * jQuery.Huisethome.js 设为首页\n * ======================================================================== */\nfunction Huisethome(obj){\n\ttry{\n\t\tobj.style.behavior=\"url(#default#homepage)\";\n\t\tobj.setHomePage(webSite);\n\t}\n\tcatch(e){\n\t\tif(window.netscape){\n\t\t\ttry {\n\t\t\t\tnetscape.security.PrivilegeManager.enablePrivilege(\"UniversalXPConnect\");\n\t\t\t\t}\n\t\t\tcatch(e){\n\t\t\t\t$.Huimodalalert(\"此操作被浏览器拒绝！\\n请在浏览器地址栏输入\\\"about:config\\\"并回车\\n然后将 [signed.applets.codebase_principal_support]的值设置为'true',双击即可。\",2000);\n\t\t\t}\n\t\t\tvar prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch);\n\t\t\tprefs.setCharPref('browser.startup.homepage',url);\n\t\t}\n\t}\n}\n\n/* =======================================================================\n * jQuery.Huisidenav.js 左侧菜单-隐藏显示\n * ======================================================================== */\nfunction displaynavbar(obj){\n\tif($(obj).hasClass(\"open\")){\n\t\t$(obj).removeClass(\"open\");\n\t\t$(\"body\").removeClass(\"big-page\");\n\t} else {\n\t\t$(obj).addClass(\"open\");\n\t\t$(\"body\").addClass(\"big-page\");\n\t}\n}\n\n/* =======================================================================\n * jQuery.Huihover.js v2.0 Huihover\n * http://www.h-ui.net/\n * Created & Modified by guojunhui\n * Date modified 2017.05.05\n *\n * Copyright 2017 北京颖杰联创科技有限公司 All rights reserved.\n * Licensed under MIT license.\n * http://opensource.org/licenses/MIT\n * ========================================================================*/\n!function($) {\n\t$.fn.Huihover = function(options){\n\t\tvar defaults = {\n\t\t\tclassName:\"hover\",\n\t\t}\n\t\tvar options = $.extend(defaults, options);\n\t\tthis.each(function(){\t\t\t\n\t\t\tvar that = $(this);\n\t\t\tthat.hover(function() {\n\t\t\t\tthat.addClass(options.className);\n\t\t\t},\n\t\t\tfunction() {\n\t\t\t\tthat.removeClass(options.className);\n\t\t\t});\n\t\t});\n\t}\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huifocusblur.js v2.0 得到失去焦点\n * http://www.h-ui.net/\n * Created & Modified by guojunhui\n * Date modified 2017.05.09\n *\n * Copyright 2017 北京颖杰联创科技有限公司 All rights reserved.\n * Licensed under MIT license.\n * http://opensource.org/licenses/MIT\n * ========================================================================*/\n!function($) {\n\t$.fn.Huifocusblur = function(options){\n\t\tvar defaults = {\n\t\t\tclassName:\"focus\",\n\t\t}\n\t\tvar options = $.extend(defaults, options);\n\t\tthis.each(function(){\t\t\t\n\t\t\tvar that = $(this);\n\t\t\tthat.focus(function() {\n\t\t\t\tthat.addClass(options.className).removeClass(\"inputError\");\n\t\t\t});\t\t\t\n\t\t\tthat.blur(function() {\n\t\t\t\tthat.removeClass(options.className);\n\t\t\t});\n\t\t});\n\t}\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huiselect.js 选择\n * ========================================================================*/\n!function($) {\n\t$.Huiselect = function(divselectid, inputselectid) {\n\t\tvar inputselect = $(inputselectid);\n\t\t$(divselectid + \" cite\").click(function() {\n\t\t\tvar ul = $(divselectid + \" ul\");\n\t\t\tul.slideToggle();\n\t\t});\n\t\t$(divselectid + \" ul li a\").click(function() {\n\t\t\tvar txt = $(this).text();\n\t\t\t$(divselectid + \" cite\").html(txt);\n\t\t\tvar value = $(this).attr(\"selectid\");\n\t\t\tinputselect.val(value);\n\t\t\t$(divselectid + \" ul\").hide();\n\t\t});\n\t\t$(document).click(function() {\n\t\t\t$(divselectid + \" ul\").hide();\n\t\t});\n\t};\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huitab.js v2.0 选项卡\n * http://www.h-ui.net/\n * Created & Modified by guojunhui\n * Date modified 2017.05.05\n *\n * Copyright 2017 北京颖杰联创科技有限公司 All rights reserved.\n * Licensed under MIT license.\n * http://opensource.org/licenses/MIT\n * ========================================================================*/\n!function($) {\n\t$.fn.Huitab = function(options){\n\t\tvar defaults = {\n\t\t\ttabBar:'.tabBar span',\n\t\t\ttabCon:\".tabCon\",\n\t\t\tclassName:\"current\",\n\t\t\ttabEvent:\"click\",\n\t\t\tindex:0,\n\t\t}\n\t\tvar options = $.extend(defaults, options);\n\t\tthis.each(function(){\n\t\t\tvar that = $(this);\n\t\t\tthat.find(options.tabBar).removeClass(options.className);\n\t\t\tthat.find(options.tabBar).eq(options.index).addClass(options.className);\n\t\t\tthat.find(options.tabCon).hide();\n\t\t\tthat.find(options.tabCon).eq(options.index).show();\n\t\t\t\n\t\t\tthat.find(options.tabBar).on(options.tabEvent,function(){\n\t\t\t\tthat.find(options.tabBar).removeClass(options.className);\n\t\t\t\t$(this).addClass(options.className);\n\t\t\t\tvar index = that.find(options.tabBar).index(this);\n\t\t\t\tthat.find(options.tabCon).hide();\n\t\t\t\tthat.find(options.tabCon).eq(index).show();\n\t\t\t});\n\t\t});\n\t}\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huifold.js v2.0 折叠\n * http://www.h-ui.net/\n * Created & Modified by guojunhui\n * Date modified 2017.05.05\n *\n * Copyright 2017 北京颖杰联创科技有限公司 All rights reserved.\n * Licensed under MIT license.\n * http://opensource.org/licenses/MIT\n * ========================================================================*/\n!function($) {\n\t$.fn.Huifold = function(options){\n\t\tvar defaults = {\n\t\t\ttitCell:'.item .Huifold-header',\n\t\t\tmainCell:'.item .Huifold-body',\n\t\t\ttype:1,//1\t只打开一个，可以全部关闭;2\t必须有一个打开;3\t可打开多个\n\t\t\ttrigger:'click',\n\t\t\tclassName:\"selected\",\n\t\t\tspeed:'first',\n\t\t}\n\t\tvar options = $.extend(defaults, options);\n\t\tthis.each(function(){\t\n\t\t\tvar that = $(this);\n\t\t\tthat.find(options.titCell).on(options.trigger,function(){\n\t\t\t\tif ($(this).next().is(\":visible\")) {\n\t\t\t\t\tif (options.type == 2) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$(this).next().slideUp(options.speed).end().removeClass(options.className);\n\t\t\t\t\t\tif ($(this).find(\"b\")) {\n\t\t\t\t\t\t\t$(this).find(\"b\").html(\"+\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}else {\n\t\t\t\t\tif (options.type == 3) {\n\t\t\t\t\t\t$(this).next().slideDown(options.speed).end().addClass(options.className);\n\t\t\t\t\t\tif ($(this).find(\"b\")) {\n\t\t\t\t\t\t\t$(this).find(\"b\").html(\"-\");\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthat.find(options.mainCell).slideUp(options.speed);\n\t\t\t\t\t\tthat.find(options.titCell).removeClass(options.className);\n\t\t\t\t\t\tif (that.find(options.titCell).find(\"b\")) {\n\t\t\t\t\t\t\tthat.find(options.titCell).find(\"b\").html(\"+\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$(this).next().slideDown(options.speed).end().addClass(options.className);\n\t\t\t\t\t\tif ($(this).find(\"b\")) {\n\t\t\t\t\t\t\t$(this).find(\"b\").html(\"-\");\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\t\n\t\t});\n\t}\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huitags.js v2.0 标签\n * http://www.h-ui.net/\n * Created & Modified by guojunhui\n * Date modified 2017.05.10\n *\n * Copyright 2017 北京颖杰联创科技有限公司 All rights reserved.\n * Licensed under MIT license.\n * http://opensource.org/licenses/MIT\n * ========================================================================*/\n!function($) {\n\t$.fn.Huitags = function(options) {\n\t\tvar defaults = {\n\t\t\tvalue:'Hui前端框架,H-ui,辉哥',\n\t\t\tmaxlength : 20,\n\t\t\tnumber : 5,\n\t\t\ttagsDefault : [\"Html\",\"CSS\",\"JS\"],\n\t\t}\n\t\tvar options = $.extend(defaults, options);\n\t\tvar keyCodes = {\n\t\t\tEnter : 13,\n\t\t\tEnter2 : 108,\n\t\t\tSpacebar:32\n\t\t}\n\t\tthis.each(function(){\n\t\t\tvar that = $(this);\n\t\t\tvar str = \n\t\t\t'<div class=\"Huitags-wraper\">'+\n\t\t\t\t'<div class=\"Huitags-editor cl\"></div>'+\n\t\t\t\t'<div class=\"Huitags-input-wraper\">'+\n\t\t\t\t\t'<input type=\"text\" class=\"input-text Huitags-input\" maxlength=\"'+options.maxlength+'\" value=\"\">'+\n\t\t\t\t'</div>'+\n\t\t\t\t'<div class=\"Huitags-list\">'+\n\t\t\t\t\t'<div class=\"Huitags-notag\" style=\"display:none\">暂无常用标签</div>'+\n\t\t\t\t\t'<div class=\"Huitags-has\"></div>'+\n\t\t\t\t'</div>'+\n\t\t\t\t'<input type=\"hidden\" class=\"Huitags-val\" name=\"\" value=\"'+options.value+'\">'+\n\t\t\t'</div>';\n\t\t\tthat.append(str);\n\t\t\tvar wraper = that.find(\".Huitags-wraper\");\n\t\t\tvar editor = that.find(\".Huitags-editor\");\n\t\t\tvar input =that.find(\".Huitags-input\");\n\t\t\tvar list = that.find(\".Huitags-list\");\n\t\t\tvar has = that.find(\".Huitags-has\");\n\t\t\tvar val = that.find(\".Huitags-val\");\n\t\t\t\n\n\t\t\t\n\t\t\tif(options.tagsDefault){\n\t\t\t\tvar tagsDefaultLength = (options.tagsDefault).length;\n\t\t\t\tfor(var i = 0;i< tagsDefaultLength; i++){\n\t\t\t\t\thas.append('<span>'+options.tagsDefault[i]+'</span>');\n\t\t\t\t}\n\t\t\t\thas.find(\"span\").on('click',function(){\n\t\t\t\t\tvar taghasV = $(this).text();\n\t\t\t\t\ttaghasV=taghasV.replace(/(^\\s*)|(\\s*$)/g,\"\");\n\t\t\t\t\teditor.append('<span class=\"Huitags-token\">'+taghasV+'</span>');\n\t\t\t\t\tgettagval(this);\n\t\t\t\t\t$(this).remove();\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\tfunction gettagval(obj) {\n\t\t\t\tvar str = \"\";\n\t\t\t\tvar token = that.find(\".Huitags-token\");\n\t\t\t\tif (token.length < 1) {\n\t\t\t\t\tinput.val(\"\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tfor (var i = 0; i < token.length; i++) {\n\t\t\t\t\tstr += token.eq(i).text() + \",\";\n\t\t\t\t}\n\t\t\t\tstr = unique(str, 1);\n\t\t\t\tstr=str.join();\n\t\t\t\tval.val(str);\n\t\t\t}\n\t\t\t/*将字符串逗号分割成数组并去重*/\n\t\t\tfunction unique(o, type){\n\t\t\t\t//去掉前后空格\n\t\t\t\to=o.replace(/(^\\s*)|(\\s*$)/g,\"\");\n\t\t\t\tif(type == 1) {\n\t\t\t\t\t//把所有的空格和中文逗号替换成英文逗号\n\t\t\t\t\to=o.replace(/(\\s)|(，)/g, \",\");\n\t\t\t\t} else {\n\t\t\t\t\t//把所有的中文逗号替换成英文逗号\n\t\t\t\t\to=o.replace(/(，)/g, \",\");\n\t\t\t\t}\n\t\t\t\t//去掉前后英文逗号\n\t\t\t\to=o.replace(/^,|,$/g, \"\");\n\t\t\t\t//去重连续的英文逗号\n\t\t\t\to=o.replace(/,+/g,',');\n\t\t\t\to=o.split(\",\");\n\t\t\t\tvar n = [o[0]]; //结果数组\n\t\t\t\tfor(var i = 1; i < o.length; i++){\n\t\t\t\t\tif (o.indexOf(o[i]) == i) {\n\t\t\t\t\t\tif(o[i] == \"\")\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tn.push(o[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn n;\n\t\t\t}\n\t\t\t\n\t\t\tinput.on(\"keydown\",function(e){\n\t\t\t\tvar evt = e || window.event;\n\t\t\t\tif (evt.keyCode == keyCodes.Enter || evt.keyCode == keyCodes.Enter2 || evt.keyCode == keyCodes.Spacebar) {\n\t\t\t\t\tvar v = input.val().replace(/\\s+/g, \"\");\n\t\t\t\t\tvar reg = /^,|,$/gi;\n\t\t\t\t\tv = v.replace(reg, \"\");\n\t\t\t\t\tv = $.trim(v);\n\t\t\t\t\tif (v != '') {\n\t\t\t\t\t\tinput.change();\n\t\t\t\t\t}else{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\tinput.on(\"change\",function(){\n\t\t\t\tvar v1 = input.val();\n\t\t\t\tvar v2 = val.val();\n\t\t\t\tvar v = v2+','+v1;\n\t\t\t\tif(v!=''){\n\t\t\t\t\tvar str='<i class=\"Huitags-icon Hui-iconfont\">&#xe64b;</i>';\n\t\t\t\t\tvar result = unique(v, 1);\n\t\t\t\t\tif(result.length>0){\n\t\t\t\t\t\tfor(var j=0;j<result.length;j++){\n\t\t\t\t\t\t\tstr+='<span class=\"Huitags-token\">'+result[j]+'</span>';\n\t\t\t\t\t\t}\n\t\t\t\t\t\tval.val(result);\n\t\t\t\t\t\teditor.html(str);\n\t\t\t\t\t\tinput.val(\"\").blur();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t\t\t\n\t\t\t$(document).on(\"click\",\".Huitags-token\",function(){\n\t\t\t\t$(this).remove();\n\t\t\t\tvar str =\"\";\n\t\t\t\tif(that.find(\".Huitags-token\").length<1){\n\t\t\t\t\tval.val(\"\");\n\t\t\t\t\treturn false;\n\t\t\t\t}else{\n\t\t\t\t\tfor(var i = 0;i< that.find(\".Huitags-token\").length;i++){\n\t\t\t\t\t\tstr += that.find(\".Huitags-token\").eq(i).text() + \",\";\n\t\t\t\t\t}\n\t\t\t\t\tstr = str.substring(0,str.length-1);\n\t\t\t\t\tval.val(str);\n\t\t\t\t}\n\t\t\t});\t\t\t\t\t\t\n\t\t\tinput.change();\n\t\t});\n\t}\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huitagsmixed.js 标签混排效果\n * ========================================================================*/\n!function($) {\n\t$.Huitagsmixed = function(obj) {\n\t\t$(obj).each(function() {\n\t\t\tvar x = 9;\n\t\t\tvar y = 0;\n\t\t\tvar rand = parseInt(Math.random() * (x - y + 1) + y);\n\t\t\t$(this).addClass(\"tags\" + rand);\n\t\t});\n\t}\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huitextarealength.js v2.0 字数限制\n * http://www.h-ui.net/\n * Created & Modified by guojunhui\n * Date modified 2017.05.12\n *\n * Copyright 2017 北京颖杰联创科技有限公司 All rights reserved.\n * Licensed under MIT license.\n * http://opensource.org/licenses/MIT\n * ========================================================================*/\n!function($) {\n\t$.fn.Huitextarealength = function(options){\n\t\tvar defaults = {\n\t\t\tminlength:0,\n\t\t\tmaxlength:140,\n\t\t\terrorClass:\"error\",\n\t\t\texceed:true,\t\t\t\n\t\t}\n\t\tvar options = $.extend(defaults, options);\n\t\tthis.each(function(){\t\t\t\n\t\t\tvar that = $(this);\n\t\t\tvar v = that.val();\n\t\t\tvar l = v.length;\n\t\t\tvar str = '<p class=\"textarea-numberbar\"><em class=\"textarea-length\">'+l+'</em>/'+options.maxlength+'</p>';\n\t\t\tthat.parent().append(str);\n\t\t\t\n\t\t\tthat.on(\"keyup\",function(){\n\t\t\t\tv = that.val();\n\t\t\t\tl = v.length;\t\t\t\t\n\t\t\t\tif (l > options.maxlength) {\n\t\t\t\t\tif(options.exceed){\n\t\t\t\t\t\tthat.addClass(options.errorClass);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tv = v.substring(0, options.maxlength);\n\t\t\t\t\t\tthat.val(v);\n\t\t\t\t\t\tthat.removeClass(options.errorClass);\n\t\t\t\t\t}\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\telse if(l<options.minlength){\n\t\t\t\t\tthat.addClass(options.errorClass);\n\t\t\t\t}else{\n\t\t\t\t\tthat.removeClass(options.errorClass);\n\t\t\t\t}\n\t\t\t\tthat.parent().find(\".textarea-length\").text(v.length);\n\t\t\t});\t\t\n\t\t\t\n\t\t});\n\t}\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huipreview.js v2.0 图片预览\n * http://www.h-ui.net/\n * Created & Modified by guojunhui\n * Date modified 2017.05.05\n *\n * Copyright 2017 北京颖杰联创科技有限公司 All rights reserved.\n * Licensed under MIT license.\n * http://opensource.org/licenses/MIT\n * ========================================================================*/\n!function($) {\n\t$.fn.Huipreview = function(options){\n\t\tvar defaults = {\n\t\t\tclassName:\"active\",\n\t\t\tbigImgWidth: 300,\n\t\t}\n\t\tvar options = $.extend(defaults, options);\n\t\tthis.each(function(){\n\t\t\tvar that = $(this);\n\t\t\tvar timer;\n\t\t\tthat.hover(\n\t\t\t\tfunction() {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\ttimer = setTimeout(function () {\n\t\t\t\t\t\t$(\"#tooltip-preview\").remove();\n\t\t\t\t\t\tvar smallImg = that.find(\"img\").attr(\"src\");\n\t\t\t\t\t\tvar bigImg = that.attr('data-src');\n\t\t\t\t\t\tvar bigImgW = that.attr('data-width');\n\t\t\t\t\t\tvar bigImgH = that.attr('data-height');\n\t\t\t\t\t\tvar winW = $(window).width();\n\t\t\t\t\t\tvar winW5 = winW / 2;\n\t\t\t\t\t\tvar imgT = that.parent().offset().top;\n\t\t\t\t\t\tvar imgL = that.parent().offset().left;\n\t\t\t\t\t\tvar imgW = that.parent().width();\n\t\t\t\t\t\tvar imgH = that.parent().height();\n\t\t\t\t\t\tvar ww = (imgL + imgW / 2);\n\t\t\t\t\t\tvar tooltipLeft = \"auto\",tooltipRight = \"auto\";\n\t\t\t\t\t\tif (ww < winW5) {\n\t\t\t\t\t\t\ttooltipLeft = (imgW + imgL) + \"px\";\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttooltipRight = (winW - imgL) + \"px\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tthat.addClass(options.className);\t\t\t\t\n\t\t\t\t\t\tif (bigImg == '') {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t} else {\t\t\t\t\t\t\n\t\t\t\t\t\t\tvar tooltip_keleyi_com = \n\t\t\t\t\t\t\t'<div id=\"preview-wraper\" style=\"position: absolute;width:'+options.bigImgWidth+'px;height:auto;top:' + imgT + 'px;right:' + tooltipRight + ';left:' + tooltipLeft + '\">'+\n\t\t\t\t\t\t\t\t'<img src=\"'+smallImg+'\" width=\"'+options.bigImgWidth+'\">'+\n\t\t\t\t\t\t\t'</div>';\n\t\t\t\t\t\t\t$(\"body\").append(tooltip_keleyi_com);\n\t\t\t\t\t\t\t/*图片预加载*/\n\t\t\t\t\t\t\tvar image = new Image();\n\t\t\t\t\t\t\timage.src = bigImg;\n\t\t\t\t\t\t\t/*创建一个Image对象*/\n\t\t\t\t\t\t\timage.onload = function() {\n\t\t\t\t\t\t\t\t$('#preview-wraper').find(\"img\").attr(\"src\",bigImg).css(\"width\",options.bigImgWidth);\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t},500);\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tthat.removeClass(options.className);\n\t\t\t\t\t$(\"#preview-wraper\").remove();\n\t\t\t\t}\n\t\t\t);\n\t\t});\n\t}\t\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huimodalalert.js alert\n * ========================================================================*/\n!function($) {\n\t$.Huimodalalert = function(info, speed) {\n\t\tif ($(\".modal-alert\").length > 0) {\n\t\t\t$(\".modal-alert\").remove();\n\t\t}\n\t\tif (speed == 0 || typeof(speed) == \"undefined\") {\n\t\t\t$(document.body).append('<div id=\"modal-alert\" class=\"modal modal-alert radius\">' + '<div class=\"modal-alert-info\">' + info + '</div>' + '<div class=\"modal-footer\"> <button class=\"btn btn-primary radius\" onClick=\"$.Huimodal_alert.hide()\">确定</button></div>' + '</div>');\n\t\t\t$(\"#modal-alert\").fadeIn();\n\t\t} else {\n\t\t\t$(document.body).append('<div id=\"modal-alert\" class=\"modal modal-alert radius\">' + '<div class=\"modal-alert-info\">' + info + '</div>' + '</div>');\n\t\t\t$(\"#modal-alert\").fadeIn();\n\t\t\tsetTimeout($.Huimodalalert.hide, speed);\n\t\t}\n\t}\n\t$.Huimodalalert.hide = function() {\n\t\t$(\"#modal-alert\").fadeOut(\"normal\",\n\t\tfunction() {\n\t\t\t$(\"#modal-alert\").remove();\n\t\t});\n\t}\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huialert.js alert\n * ========================================================================*/\n!function($) {\n\t$.Huialert = function() {\n\t\t$(\".Huialert i\").Huihover();\n\t\t$(\".Huialert i\").on(\"click\",function() {\n\t\t\tvar Huialert = $(this).parents(\".Huialert\");\n\t\t\tHuialert.fadeOut(\"normal\",\n\t\t\tfunction() {\n\t\t\t\tHuialert.remove();\n\t\t\t});\n\t\t});\n\t}\n\t$.Huialert();\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huitotop.js v2.0 返回顶部\n * http://www.h-ui.net/\n * Created & Modified by guojunhui\n * Date modified 2017.05.05\n *\n * Copyright 2017 北京颖杰联创科技有限公司 All rights reserved.\n * Licensed under MIT license.\n * http://opensource.org/licenses/MIT\n * ========================================================================*/\n!function($) {\n\t//bottom 距离底部高度\n\t$.Huitotop = function(bottom){\t\t\n\t\tif(!bottom){\n\t\t\tbottom = 60;\n\t\t}\n\t\tvar str ='<a href=\"javascript:void(0)\" class=\"tools-right toTop Hui-iconfont\" title=\"返回顶部\" alt=\"返回顶部\" style=\"display:none;bottom:'+bottom+'px\">&#xe684;</a>';\n\t\t$(str).appendTo($('body')).click(function() {\n\t\t\t$(\"html, body\").animate({\n\t\t\t\tscrollTop: 0\n\t\t\t},\n\t\t\t120);\n\t\t});\n\t\tvar backToTopFun = function(){\n\t\t\tvar st = $(document).scrollTop();\n\t\t\tvar winh = $(window).height();\n\t\t\tif(st> 0){\n\t\t\t\t$(\".toTop\").show();\n\t\t\t}else{\n\t\t\t\t$(\".toTop\").hide();\n\t\t\t}\n\t\t\t/*IE6下的定位*/\n\t\t\tif (!window.XMLHttpRequest) {\n\t\t\t\t$(\".toTop\").css(\"top\", st + winh - 166);\n\t\t\t}\n\t\t\t\n\t\t}\t\t\n\t\t$(window).on(\"scroll\",backToTopFun);\t\n\t}\n} (window.jQuery);\n\n/* =======================================================================\n * jQuery.Huimarquee.js 滚动\n * ========================================================================*/\n!function($) {\n\t$.Huimarquee = function(height, speed, delay) {\n\t\tvar scrollT;\n\t\tvar pause = false;\n\t\tvar ScrollBox = document.getElementById(\"marquee\");\n\t\tif (document.getElementById(\"holder\").offsetHeight <= height) return;\n\t\tvar _tmp = ScrollBox.innerHTML.replace('holder', 'holder2');\n\t\tScrollBox.innerHTML += _tmp;\n\t\tScrollBox.onmouseover = function() {\n\t\t\tpause = true;\n\t\t}\n\t\tScrollBox.onmouseout = function() {\n\t\t\tpause = false;\n\t\t}\n\t\tScrollBox.scrollTop = 0;\n\t\tvar start = function() {\n\t\t\tscrollT = setInterval(scrolling, speed);\n\t\t\tif (!pause) ScrollBox.scrollTop += 2;\n\t\t}\n\t\tvar scrolling = function() {\n\t\t\tif (ScrollBox.scrollTop % height != 0) {\n\t\t\t\tScrollBox.scrollTop += 2;\n\t\t\t\tif (ScrollBox.scrollTop >= ScrollBox.scrollHeight / 2) ScrollBox.scrollTop = 0;\n\t\t\t} else {\n\t\t\t\tclearInterval(scrollT);\n\t\t\t\tsetTimeout(start, delay);\n\t\t\t}\n\t\t}\n\t\tsetTimeout(start, delay);\n\t}\n} (window.jQuery);\n\n$(function() {\n\t/*全选*/\n\t$(\"table thead th input:checkbox\").on(\"click\",function() {\n\t\t$(this).closest(\"table\").find(\"tr > td:first-child input:checkbox\").prop(\"checked\", $(\"table thead th input:checkbox\").prop(\"checked\"));\n\t});\n\n\t/*上传*/\n\t$(document).on(\"change\", \".input-file\",function() {\n\t\tvar uploadVal = $(this).val();\n\t\t$(this).parent().find(\".upload-url\").val(uploadVal).focus().blur();\n\t});\n});\n\n/* ========================================================================\n * Bootstrap.button.js v3.3.0\n * http://getbootstrap.com/javascript/#buttons\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n!function($) {\n\t'use strict';\n\t// BUTTON PUBLIC CLASS DEFINITION\n\t// ==============================\n\tvar Button = function(element, options) {\n\t\tthis.$element = $(element);\n\t\tthis.options = $.extend({},Button.DEFAULTS, options);\n\t\tthis.isLoading = false;\n\t}\n\tButton.VERSION = '3.3.0'\n\n\tButton.DEFAULTS = {\n\t\tloadingText: 'loading...'\n\t}\n\n\tButton.prototype.setState = function(state) {\n\t\tvar d = 'disabled'\n\t\tvar $el = this.$element\n\t\tvar val = $el.is('input') ? 'val': 'html'\n\t\tvar data = $el.data();\n\t\tstate = state + 'Text';\n\t\tif (data.resetText == null) $el.data('resetText', $el[val]());\n\t\t// push to event loop to allow forms to submit\n\t\tsetTimeout($.proxy(function() {\n\t\t\t$el[val](data[state] == null ? this.options[state] : data[state]);\n\t\t\tif (state == 'loadingText') {\n\t\t\t\tthis.isLoading = true;\n\t\t\t\t$el.addClass(d).attr(d, d);\n\t\t\t} else if (this.isLoading) {\n\t\t\t\tthis.isLoading = false;\n\t\t\t\t$el.removeClass(d).removeAttr(d);\n\t\t\t}\n\t\t},\n\t\tthis), 0)\n\t}\n\n\tButton.prototype.toggle = function() {\n\t\tvar changed = true;\n\t\tvar $parent = this.$element.closest('[data-toggle=\"buttons\"]');\n\n\t\tif ($parent.length) {\n\t\t\tvar $input = this.$element.find('input');\n\t\t\tif ($input.prop('type') == 'radio') {\n\t\t\t\tif ($input.prop('checked') && this.$element.hasClass('active')) changed = false\n\t\t\t\telse $parent.find('.active').removeClass('active')\n\t\t\t}\n\t\t\tif (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')\n\t\t} else {\n\t\t\tthis.$element.attr('aria-pressed', !this.$element.hasClass('active'))\n\t\t}\n\n\t\tif (changed) this.$element.toggleClass('active')\n\t}\n\n\t// BUTTON PLUGIN DEFINITION\n\t// ========================\n\tfunction Plugin(option) {\n\t\treturn this.each(function() {\n\t\t\tvar $this = $(this);\n\t\t\tvar data = $this.data('bs.button');\n\t\t\tvar options = typeof option == 'object' && option;\n\t\t\tif (!data) $this.data('bs.button', (data = new Button(this, options)))\n\n\t\t\tif (option == 'toggle') data.toggle()\n\t\t\telse if (option) data.setState(option)\n\t\t})\n\t}\n\n\tvar old = $.fn.button;\n\n\t$.fn.button = Plugin;\n\t$.fn.button.Constructor = Button;\n\t// BUTTON NO CONFLICT\n\t// ==================\n\t$.fn.button.noConflict = function() {\n\t\t$.fn.button = old;\n\t\treturn this;\n\t}\n\n\t// BUTTON DATA-API\n\t// ===============\n\t$(document).on('click.bs.button.data-api', '[data-toggle^=\"button\"]',\n\tfunction(e) {\n\t\tvar $btn = $(e.target);\n\t\tif (!$btn.hasClass('btn'));\n\t\t$btn = $btn.closest('.btn');\n\t\tPlugin.call($btn, 'toggle');\n\t\te.preventDefault();\n\t}).on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^=\"button\"]',\n\tfunction(e) {\n\t\t$(e.target).closest('.btn').toggleClass('focus', e.type == 'focus');\n\t})\n} (jQuery);\n\n/* =======================================================================\n * jQuery.stickUp.js v0.5.7 BETA  by:LiranCohen\n * https://github.com/LiranCohen/stickUp\n * ======================================================================== */\njQuery(function($) {\n\t$(document).ready(function(){\n\t\tvar contentButton = [];\n\t\tvar contentTop = [];\n\t\tvar content = [];\n\t\tvar lastScrollTop = 0;\n\t\tvar scrollDir = '';\n\t\tvar itemClass = '';\n\t\tvar itemHover = '';\n\t\tvar menuSize = null;\n\t\tvar stickyHeight = 0;\n\t\tvar stickyMarginB = 0;\n\t\tvar currentMarginT = 0;\n\t\tvar topMargin = 0;\n\t\tvar vartop = 0;\n\t\t$(window).scroll(function(event){\n   \t\t\tvar st = $(this).scrollTop();\n   \t\t\tif (st > lastScrollTop){\n       \t\t\tscrollDir = 'down';\n   \t\t\t} else {\n      \t\t\tscrollDir = 'up';\n   \t\t\t}\n  \t\t\tlastScrollTop = st;\n\t\t});\n\t\t$.fn.stickUp = function( options ) {\n\t\t\t// adding a class to users div\n\t\t\t$(this).addClass('stuckMenu');\n        \t//getting options\n        \tvar objn = 0;\n        \tif(options != null) {\n\t        \tfor(var o in options.parts) {\n\t        \t\tif (options.parts.hasOwnProperty(o)){\n\t        \t\t\tcontent[objn] = options.parts[objn];\n\t        \t\t\tobjn++;\n\t        \t\t}\n\t        \t}\n\t  \t\t\tif(objn == 0) {\n\t  \t\t\t\tconsole.log('error:needs arguments');\n\t  \t\t\t}\n\n\t  \t\t\titemClass = options.itemClass;\n\t  \t\t\titemHover = options.itemHover;\n\t  \t\t\tif(options.topMargin != null) {\n\t  \t\t\t\tif(options.topMargin == 'auto') {\n\t  \t\t\t\t\ttopMargin = parseInt($('.stuckMenu').css('margin-top'));\n\t  \t\t\t\t} else {\n\t  \t\t\t\t\tif(isNaN(options.topMargin) && options.topMargin.search(\"px\") > 0){\n\t  \t\t\t\t\t\ttopMargin = parseInt(options.topMargin.replace(\"px\",\"\"));\n\t  \t\t\t\t\t} else if(!isNaN(parseInt(options.topMargin))) {\n\t  \t\t\t\t\t\ttopMargin = parseInt(options.topMargin);\n\t  \t\t\t\t\t} else {\n\t  \t\t\t\t\t\tconsole.log(\"incorrect argument, ignored.\");\n\t  \t\t\t\t\t\ttopMargin = 0;\n\t  \t\t\t\t\t}\t\n\t  \t\t\t\t}\n\t  \t\t\t} else {\n\t  \t\t\t\ttopMargin = 0;\n\t  \t\t\t}\n\t  \t\t\tmenuSize = $('.'+itemClass).size();\n  \t\t\t}\t\t\t\n\t\t\tstickyHeight = parseInt($(this).height());\n\t\t\tstickyMarginB = parseInt($(this).css('margin-bottom'));\n\t\t\tcurrentMarginT = parseInt($(this).next().closest('div').css('margin-top'));\n\t\t\tvartop = parseInt($(this).offset().top);\n\t\t\t//$(this).find('*').removeClass(itemHover);\n\t\t}\n\t\t$(document).on('scroll', function() {\n\t\t\tvarscroll = parseInt($(document).scrollTop());\n\t\t\tif(menuSize != null){\n\t\t\t\tfor(var i=0;i < menuSize;i++)\n\t\t\t\t{\n\t\t\t\t\tcontentTop[i] = $('#'+content[i]+'').offset().top;\n\t\t\t\t\tfunction bottomView(i) {\n\t\t\t\t\t\tcontentView = $('#'+content[i]+'').height()*.4;\n\t\t\t\t\t\ttestView = contentTop[i] - contentView;\n\t\t\t\t\t\tif(varscroll > testView){\n\t\t\t\t\t\t\t$('.'+itemClass).removeClass(itemHover);\n\t\t\t\t\t\t\t$('.'+itemClass+':eq('+i+')').addClass(itemHover);\n\t\t\t\t\t\t} else if(varscroll < 50){\n\t\t\t\t\t\t\t$('.'+itemClass).removeClass(itemHover);\n\t\t\t\t\t\t\t$('.'+itemClass+':eq(0)').addClass(itemHover);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(scrollDir == 'down' && varscroll > contentTop[i]-50 && varscroll < contentTop[i]+50) {\n\t\t\t\t\t\t$('.'+itemClass).removeClass(itemHover);\n\t\t\t\t\t\t$('.'+itemClass+':eq('+i+')').addClass(itemHover);\n\t\t\t\t\t}\n\t\t\t\t\tif(scrollDir == 'up') {\n\t\t\t\t\t\tbottomView(i);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(vartop < varscroll + topMargin){\n\t\t\t\t$('.stuckMenu').addClass('isStuck');\n\t\t\t\t$('.stuckMenu').next().closest('div').css({\n\t\t\t\t\t'margin-top': stickyHeight + stickyMarginB + currentMarginT + 'px'\n\t\t\t\t}, 10);\n\t\t\t\t$('.stuckMenu').css(\"position\",\"fixed\");\n\t\t\t\t$('.isStuck').css({\n\t\t\t\t\ttop: '0px'\n\t\t\t\t}, 10, function(){\n\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tif(varscroll + topMargin < vartop){\n\t\t\t\t$('.stuckMenu').removeClass('isStuck');\n\t\t\t\t$('.stuckMenu').next().closest('div').css({\n\t\t\t\t\t'margin-top': currentMarginT + 'px'\n\t\t\t\t}, 10);\n\t\t\t\t$('.stuckMenu').css(\"position\",\"relative\");\n\t\t\t};\n\t\t});\n\t});\n});\n\n/* =======================================================================\n * Bootstrap.modal.js v3.3.0\n * http://getbootstrap.com/javascript/#modals\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n!function($) {\n\t'use strict';\n\t// MODAL CLASS DEFINITION\n\t// ======================\t\n\tvar Modal = function(element, options) {\n\t\tthis.options = options;\n\t\tthis.$body = $(document.body);\n\t\tthis.$element = $(element);\n\t\tthis.$backdrop = \n\t\tthis.isShown = null;\n\t\tthis.scrollbarWidth = 0;\n\n\t\tif (this.options.remote) {\n\t\t\tthis.$element.find('.modal-content').load(this.options.remote, $.proxy(function() {\n\t\t\t\tthis.$element.trigger('loaded.bs.modal');\n\t\t\t},\n\t\t\tthis))\n\t\t}\n\t}\n\n\tModal.VERSION = '3.3.0';\n\tModal.TRANSITION_DURATION = 300;\n\tModal.BACKDROP_TRANSITION_DURATION = 150;\n\n\tModal.DEFAULTS = {\n\t\tbackdrop: true,\n\t\tkeyboard: true,\n\t\tshow: true,\n\t}\n\n\tModal.prototype.toggle = function(_relatedTarget) {\n\t\treturn this.isShown ? this.hide() : this.show(_relatedTarget)\n\t}\n\n\tModal.prototype.show = function(_relatedTarget) {\n\t\tvar that = this;\n\t\tvar e = $.Event('show.bs.modal', {\n\t\t\trelatedTarget: _relatedTarget\n\t\t});\n\n\t\tthis.$element.trigger(e);\n\t\tif (this.isShown || e.isDefaultPrevented()) return;\n\t\tthis.isShown = true;\n\t\tthis.checkScrollbar();\n\t\tthis.$body.addClass('modal-open');\n\t\tthis.setScrollbar();\n\t\tthis.escape();\n\t\tthis.$element.on('click.dismiss.bs.modal', '[data-dismiss=\"modal\"]', $.proxy(this.hide, this));\n\n\t\tthis.backdrop(function() {\n\t\t\tvar transition = $.support.transition && that.$element.hasClass('fade');\n\t\t\tif (!that.$element.parent().length) {\n\t\t\t\tthat.$element.appendTo(that.$body); // don't move modals dom position\n\t\t\t}\n\t\t\tthat.$element.show().scrollTop(0);\n\t\t\tif (transition) {\n\t\t\t\tthat.$element[0].offsetWidth; // force reflow\n\t\t\t}\n\t\t\tthat.$element.addClass('in').attr('aria-hidden', false);\n\n\t\t\tthat.enforceFocus();\n\n\t\t\tvar e = $.Event('shown.bs.modal', {\n\t\t\t\trelatedTarget: _relatedTarget\n\t\t\t})\n\n\t\t\ttransition ? that.$element.find('.modal-dialog') // wait for modal to slide in\n\t\t\t.one('bsTransitionEnd',\n\t\t\tfunction() {\n\t\t\t\tthat.$element.trigger('focus').trigger(e)\n\t\t\t}).emulateTransitionEnd(Modal.TRANSITION_DURATION) : that.$element.trigger('focus').trigger(e)\n\t\t})\n\t}\n\n\tModal.prototype.hide = function(e) {\n\t\tif (e) e.preventDefault();\n\t\te = $.Event('hide.bs.modal');\n\t\tthis.$element.trigger(e);\n\t\tif (!this.isShown || e.isDefaultPrevented()) return;\n\t\tthis.isShown = false;\n\t\tthis.escape();\n\t\t$(document).off('focusin.bs.modal');\n\t\tthis.$element.removeClass('in').attr('aria-hidden', true).off('click.dismiss.bs.modal');\n\t\t$.support.transition && this.$element.hasClass('fade') ? this.$element.one('bsTransitionEnd', $.proxy(this.hideModal, this)).emulateTransitionEnd(Modal.TRANSITION_DURATION) : this.hideModal()\n\t}\n\n\tModal.prototype.enforceFocus = function() {\n\t\t$(document).off('focusin.bs.modal') // guard against infinite focus loop\n\t\t.on('focusin.bs.modal', $.proxy(function(e) {\n\t\t\tif (this.$element[0] !== e.target && !this.$element.has(e.target).length) {\n\t\t\t\tthis.$element.trigger('focus')\n\t\t\t}\n\t\t},\n\t\tthis))\n\t}\n\n\tModal.prototype.escape = function() {\n\t\tif (this.isShown && this.options.keyboard) {\n\t\t\tthis.$element.on('keydown.dismiss.bs.modal', $.proxy(function(e) {\n\t\t\t\te.which == 27 && this.hide()\n\t\t\t},\n\t\t\tthis))\n\t\t} else if (!this.isShown) {\n\t\t\tthis.$element.off('keydown.dismiss.bs.modal')\n\t\t}\n\t}\n\n\tModal.prototype.hideModal = function() {\n\t\tvar that = this;\n\t\tthis.$element.hide();\n\t\tthis.backdrop(function() {\n\t\t\tthat.$body.removeClass('modal-open');\n\t\t\tthat.resetScrollbar();\n\t\t\tthat.$element.trigger('hidden.bs.modal');\n\t\t})\n\t}\n\n\tModal.prototype.removeBackdrop = function() {\n\t\tthis.$backdrop && this.$backdrop.remove();\n\t\tthis.$backdrop = null;\n\t}\n\n\tModal.prototype.backdrop = function(callback) {\n\t\tvar that = this\n\t\tvar animate = this.$element.hasClass('fade') ? 'fade': ''\n\n\t\tif (this.isShown && this.options.backdrop) {\n\t\t\tvar doAnimate = $.support.transition && animate\n\n\t\t\tthis.$backdrop = $('<div class=\"modal-backdrop ' + animate + '\" />').prependTo(this.$element).on('click.dismiss.bs.modal', $.proxy(function(e) {\n\t\t\t\tif (e.target !== e.currentTarget) return this.options.backdrop == 'static' ? this.$element[0].focus.call(this.$element[0]) : this.hide.call(this)\n\t\t\t},\n\t\t\tthis))\n\n\t\t\tif (doAnimate) this.$backdrop[0].offsetWidth; // force reflow\n\t\t\tthis.$backdrop.addClass('in');\n\t\t\tif (!callback) return;\n\t\t\tdoAnimate ? this.$backdrop.one('bsTransitionEnd', callback).emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : callback();\n\t\t} else if (!this.isShown && this.$backdrop) {\n\t\t\tthis.$backdrop.removeClass('in');\n\t\t\tvar callbackRemove = function() {\n\t\t\t\tthat.removeBackdrop();\n\t\t\t\tcallback && callback();\n\t\t\t}\n\t\t\t$.support.transition && this.$element.hasClass('fade') ? this.$backdrop.one('bsTransitionEnd', callbackRemove).emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : callbackRemove()\n\n\t\t} else if (callback) {\n\t\t\tcallback();\n\t\t}\n\t}\n\n\tModal.prototype.checkScrollbar = function() {\n\t\tthis.scrollbarWidth = this.measureScrollbar();\n\t}\n\n\tModal.prototype.setScrollbar = function() {\n\t\tvar bodyPad = parseInt((this.$body.css('padding-right') || 0), 10);\n\t\tif (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth);\n\t}\n\n\tModal.prototype.resetScrollbar = function() {\n\t\tthis.$body.css('padding-right', '')\n\t}\n\n\tModal.prototype.measureScrollbar = function() { // thx walsh\n\t\tif (document.body.clientWidth >= window.innerWidth) return 0\n\t\tvar scrollDiv = document.createElement('div');\n\t\tscrollDiv.className = 'modal-scrollbar-measure';\n\t\tthis.$body.append(scrollDiv);\n\t\tvar scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;\n\t\tthis.$body[0].removeChild(scrollDiv);\n\t\treturn scrollbarWidth;\n\t}\n\n\t// MODAL PLUGIN DEFINITION\n\t// =======================\n\tfunction Plugin(option, _relatedTarget) {\n\t\treturn this.each(function() {\n\t\t\tvar $this = $(this);\n\t\t\tvar data = $this.data('bs.modal');\n\t\t\tvar options = $.extend({},Modal.DEFAULTS, $this.data(), typeof option == 'object' && option);\n\t\t\tif (!data) $this.data('bs.modal', (data = new Modal(this, options)));\n\t\t\tif (typeof option == 'string') data[option](_relatedTarget);\n\t\t\telse if (options.show) data.show(_relatedTarget);\n\t\t})\n\t}\n\n\tvar old = $.fn.modal;\n\t$.fn.modal = Plugin;\n\t$.fn.modal.Constructor = Modal;\n\n\t// MODAL NO CONFLICT\n\t// =================\n\t$.fn.modal.noConflict = function() {\n\t\t$.fn.modal = old;\n\t\treturn this;\n\t}\n\n\t// MODAL DATA-API\n\t// ==============\n\t$(document).on('click.bs.modal.data-api', '[data-toggle=\"modal\"]',\n\tfunction(e) {\n\t\tvar $this = $(this);\n\t\tvar href = $this.attr('href');\n\t\tvar $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\\s]+$)/, ''))); // strip for ie7\n\t\tvar option = $target.data('bs.modal') ? 'toggle': $.extend({remote: !/#/.test(href) && href},$target.data(), $this.data());\n\n\t\tif ($this.is('a')) e.preventDefault();\n\t\t$target.one('show.bs.modal',function(showEvent) {\n\t\t\tif (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown\n\t\t\t$target.one('hidden.bs.modal',function() {\n\t\t\t\t$this.is(':visible') && $this.trigger('focus');\n\t\t\t});\n\t\t});\n\t\tPlugin.call($target, option, this);\n\t});\n} (window.jQuery);\n\n/* =======================================================================\n * Bootstrap.dropdown.js v3.3.0\n * http://getbootstrap.com/javascript/#dropdowns\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n!function($) {\n\t'use strict';\n\tvar backdrop = '.dropdown-backdrop';\n\tvar toggle = '[data-toggle=\"dropdown\"]';\n\tvar Dropdown = function(element) {\n\t\t$(element).on('click.bs.dropdown', this.toggle)\n\t}\n\tDropdown.VERSION = '3.3.5';\n\tfunction getParent($this) {\n\t\tvar selector = $this.attr('data-target');\n\t\tif (!selector) {\n\t\t\tselector = $this.attr('href');\n\t\t\tselector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\\s]*$)/, ''); // strip for ie7\n\t\t}\n\t\tvar $parent = selector && $(selector);\n\t\treturn $parent && $parent.length ? $parent: $this.parent();\n\t}\n\tfunction clearMenus(e) {\n\t\tif (e && e.which === 3) return $(backdrop).remove();\n\t\t$(toggle).each(function() {\n\t\t\tvar $this = $(this);\n\t\t\tvar $parent = getParent($this);\n\t\t\tvar relatedTarget = {\n\t\t\t\trelatedTarget: this\n\t\t\t}\n\t\t\tif (!$parent.hasClass('open')) return;\n\t\t\tif (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget));\n\t\t\tif (e.isDefaultPrevented()) return;\n\t\t\t$this.attr('aria-expanded', 'false');\n\t\t\t$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget);\n\t\t});\n\t}\n\tDropdown.prototype.toggle = function(e) {\n\t\tvar $this = $(this);\n\t\tif ($this.is('.disabled, :disabled')) return;\n\t\tvar $parent = getParent($this);\n\t\tvar isActive = $parent.hasClass('open');\n\t\tclearMenus();\n\t\tif (!isActive) {\n\t\t\tif ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {\n\t\t\t\t// if mobile we use a backdrop because click events don't delegate\n\t\t\t\t$(document.createElement('div')).addClass('dropdown-backdrop').insertAfter($(this)).on('click', clearMenus);\n\t\t\t}\n\t\t\tvar relatedTarget = {\n\t\t\t\trelatedTarget: this\n\t\t\t}\n\t\t\t$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget));\n\t\t\tif (e.isDefaultPrevented()) return $this.trigger('focus').attr('aria-expanded', 'true');\n\t\t\t$parent.toggleClass('open').trigger('shown.bs.dropdown', relatedTarget);\n\t\t}\n\t\treturn false;\n\t}\n\tDropdown.prototype.keydown = function(e) {\n\t\tif (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return;\n\t\tvar $this = $(this);\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tif ($this.is('.disabled, :disabled')) return;\n\t\tvar $parent = getParent($this);\n\t\tvar isActive = $parent.hasClass('open');\n\t\tif (!isActive && e.which != 27 || isActive && e.which == 27) {\n\t\t\tif (e.which == 27)\n\t\t\t$parent.find(toggle).trigger('focus');\n\t\t\treturn;\n\t\t\t$this.trigger('click');\n\t\t}\n\t\tvar desc = ' li:not(.disabled):visible a';\n\t\tvar $items = $parent.find('.dropdown-menu' + desc);\n\t\tif (!$items.length) return;\n\t\tvar index = $items.index(e.target);\n\t\tif (e.which == 38 && index > 0) index-- // up\n\t\tif (e.which == 40 && index < $items.length - 1) index++; // down\n\t\tif (!~index) index = 0;\n\t\t$items.eq(index).trigger('focus');\n\t}\n\tfunction Plugin(option) {\n\t\treturn this.each(function() {\n\t\t\tvar $this = $(this);\n\t\t\tvar data = $this.data('bs.dropdown');\n\t\t\tif (!data) {\n\t\t\t\t$this.data('bs.dropdown', (data = new Dropdown(this)));\n\t\t\t}\n\t\t\tif (typeof option == 'string') {\n\t\t\t\tdata[option].call($this);\n\t\t\t}\n\t\t});\n\t}\n\tvar old = $.fn.dropdown;\n\t$.fn.dropdown = Plugin;\n\t$.fn.dropdown.Constructor = Dropdown;\n\t$.fn.dropdown.noConflict = function() {\n\t\t$.fn.dropdown = old;\n\t\treturn this;\n\t}\n\t$(document).on('click.bs.dropdown.data-api', clearMenus).on('click.bs.dropdown.data-api', '.dropdown form',\n\tfunction(e) {\n\t\te.stopPropagation()\n\t}).on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle).on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown).on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown);\n} (window.jQuery);\n$(function() {\n\t/*下拉菜单*/\n\t$(document).on(\"mouseenter\", \".dropDown\",\n\tfunction() {\n\t\t$(this).addClass(\"hover\");\n\t});\n\t$(document).on(\"mouseleave\", \".dropDown\",\n\tfunction() {\n\t\t$(this).removeClass(\"hover\");\n\t});\n\t$(document).on(\"mouseenter\", \".dropDown_hover\",\n\tfunction() {\n\t\t$(this).addClass(\"open\");\n\t});\n\t$(document).on(\"mouseleave\", \".dropDown_hover\",\n\tfunction() {\n\t\t$(this).removeClass(\"open\");\n\t});\n\t$(document).on(\"click\", \".dropDown-menu li a\",\n\tfunction() {\n\t\t$(\".dropDown\").removeClass('open');\n\t});\n\t$(document).on(\"mouseenter\", \".menu > li\",\n\tfunction() {\n\t\t$(this).addClass(\"open\");\n\t});\n\t$(document).on(\"mouseleave\", \".menu > li\",\n\tfunction() {\n\t\t$(this).removeClass(\"open\");\n\t});\n});\n\n/* =======================================================================\n * Bootstrap.transition.js v3.3.0\n * http://getbootstrap.com/javascript/#transitions\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n!function ($) {\n\t'use strict';\t\n\tfunction transitionEnd() {\n\t\tvar el = document.createElement('bootstrap');\t\n\t\tvar transEndEventNames = {\n\t\t\tWebkitTransition : 'webkitTransitionEnd',\n\t\t\tMozTransition    : 'transitionend',\n\t\t\tOTransition      : 'oTransitionEnd otransitionend',\n\t\t\ttransition       : 'transitionend'\n\t\t}\t\n\t\tfor (var name in transEndEventNames) {\n\t\t\tif (el.style[name] !== undefined) {\n\t\t\t\treturn { end: transEndEventNames[name] }\n\t\t\t}\n\t\t}\t\t\n\t\treturn false // explicit for ie8 (  ._.)\n\t}\t\n\t// http://blog.alexmaccaw.com/css-transitions\n\t$.fn.emulateTransitionEnd = function (duration) {\n\t\tvar called = false;\n\t\tvar $el = this;\n\t\t$(this).one('bsTransitionEnd', function () { called = true })\n\t\tvar callback = function () {\n\t\t\tif (!called) $($el).trigger($.support.transition.end)\n\t\t}\n\t\tsetTimeout(callback, duration);\n\t\treturn this;\n\t}\t\n\t$(function () {\n\t\t$.support.transition = transitionEnd();\t\n\t\tif (!$.support.transition) return;\n\t\t$.event.special.bsTransitionEnd = {\n\t\t\tbindType: $.support.transition.end,\n\t\t\tdelegateType: $.support.transition.end,\n\t\t\thandle: function (e) {\n\t\t\t\tif ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments);\n\t\t\t}\n\t\t}\n\t})\t\n}(window.jQuery);\n\n/* =======================================================================\n * Bootstrap.tooltip.js v3.3.0\n * http://getbootstrap.com/javascript/#tooltip\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n!function($) {\n\t'use strict';\n\n\t// TOOLTIP PUBLIC CLASS DEFINITION\n\t// ===============================\n\tvar Tooltip = function(element, options) {\n\t\tthis.type = this.options = this.enabled = this.timeout = this.hoverState = this.$element = null;\n\t\tthis.init('tooltip', element, options);\n\t}\n\n\tTooltip.VERSION = '3.3.0';\n\tTooltip.TRANSITION_DURATION = 150;\n\n\tTooltip.DEFAULTS = {\n\t\tanimation: true,\n\t\tplacement: 'top',\n\t\tselector: false,\n\t\ttemplate: '<div class=\"tooltip\" role=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>',\n\t\ttrigger: 'hover focus',\n\t\ttitle: '',\n\t\tdelay: 0,\n\t\thtml: false,\n\t\tcontainer: false,\n\t\tviewport: {\n\t\t\tselector: 'body',\n\t\t\tpadding: 0\n\t\t}\n\t}\n\n\tTooltip.prototype.init = function(type, element, options) {\n\t\tthis.enabled = true;\n\t\tthis.type = type;\n\t\tthis.$element = $(element);\n\t\tthis.options = this.getOptions(options);\n\t\tthis.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport);\n\n\t\tvar triggers = this.options.trigger.split(' ');\n\t\tfor (var i = triggers.length; i--;) {\n\t\t\tvar trigger = triggers[i];\n\t\t\tif (trigger == 'click') {\n\t\t\t\tthis.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this));\n\t\t\t} else if (trigger != 'manual') {\n\t\t\t\tvar eventIn = trigger == 'hover' ? 'mouseenter': 'focusin';\n\t\t\t\tvar eventOut = trigger == 'hover' ? 'mouseleave': 'focusout';\n\t\t\t\tthis.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this));\n\t\t\t\tthis.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this));\n\t\t\t}\n\t\t}\n\n\t\tthis.options.selector ? (this._options = $.extend({},\n\t\tthis.options, {\n\t\t\ttrigger: 'manual',\n\t\t\tselector: ''\n\t\t})) : this.fixTitle()\n\t}\n\n\tTooltip.prototype.getDefaults = function() {\n\t\treturn Tooltip.DEFAULTS;\n\t}\n\n\tTooltip.prototype.getOptions = function(options) {\n\t\toptions = $.extend({},\n\t\tthis.getDefaults(), this.$element.data(), options);\n\t\tif (options.delay && typeof options.delay == 'number') {\n\t\t\toptions.delay = {\n\t\t\t\tshow: options.delay,\n\t\t\t\thide: options.delay\n\t\t\t}\n\t\t}\n\t\treturn options;\n\t}\n\n\tTooltip.prototype.getDelegateOptions = function() {\n\t\tvar options = {}\n\t\tvar defaults = this.getDefaults()\n\n\t\tthis._options && $.each(this._options,\n\t\tfunction(key, value) {\n\t\t\tif (defaults[key] != value) options[key] = value;\n\t\t})\n\n\t\treturn options;\n\t}\n\n\tTooltip.prototype.enter = function(obj) {\n\t\tvar self = obj instanceof this.constructor ? \n\t\tobj: $(obj.currentTarget).data('bs.' + this.type);\n\n\t\tif (self && self.$tip && self.$tip.is(':visible')) {\n\t\t\tself.hoverState = 'in';\n\t\t\treturn;\n\t\t}\n\n\t\tif (!self) {\n\t\t\tself = new this.constructor(obj.currentTarget, this.getDelegateOptions());\n\t\t\t$(obj.currentTarget).data('bs.' + this.type, self);\n\t\t}\n\n\t\tclearTimeout(self.timeout);\n\t\tself.hoverState = 'in';\n\t\tif (!self.options.delay || !self.options.delay.show) return self.show()\n\n\t\tself.timeout = setTimeout(function() {\n\t\t\tif (self.hoverState == 'in') self.show();\n\t\t},\n\t\tself.options.delay.show);\n\t}\n\n\tTooltip.prototype.leave = function(obj) {\n\t\tvar self = obj instanceof this.constructor ? obj: $(obj.currentTarget).data('bs.' + this.type);\n\n\t\tif (!self) {\n\t\t\tself = new this.constructor(obj.currentTarget, this.getDelegateOptions());\n\t\t\t$(obj.currentTarget).data('bs.' + this.type, self);\n\t\t}\n\t\tclearTimeout(self.timeout);\n\t\tself.hoverState = 'out';\n\n\t\tif (!self.options.delay || !self.options.delay.hide) return self.hide();\n\t\tself.timeout = setTimeout(function() {\n\n\t\t\tif (self.hoverState == 'out') self.hide();\n\t\t},\n\t\tself.options.delay.hide);\n\t}\n\n\tTooltip.prototype.show = function() {\n\t\tvar e = $.Event('show.bs.' + this.type);\n\t\tif (this.hasContent() && this.enabled) {\n\t\t\tthis.$element.trigger(e);\n\n\t\t\tvar inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]);\n\t\t\tif (e.isDefaultPrevented() || !inDom) return;\n\t\t\tvar that = this;\n\t\t\tvar $tip = this.tip();\n\t\t\tvar tipId = this.getUID(this.type);\n\n\t\t\tthis.setContent();\n\t\t\t$tip.attr('id', tipId);\n\t\t\tthis.$element.attr('aria-describedby', tipId);\n\n\t\t\tif (this.options.animation) $tip.addClass('fade');\n\n\t\t\tvar placement = typeof this.options.placement == 'function' ? this.options.placement.call(this, $tip[0], this.$element[0]) : this.options.placement;\n\n\t\t\tvar autoToken = /\\s?auto?\\s?/i;\n\t\t\tvar autoPlace = autoToken.test(placement);\n\t\t\tif (autoPlace) placement = placement.replace(autoToken, '') || 'top';\n\n\t\t\t$tip.detach().css({\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\tdisplay: 'block'\n\t\t\t}).addClass(placement).data('bs.' + this.type, this);\n\n\t\t\tthis.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element);\n\t\t\tvar pos = this.getPosition();\n\t\t\tvar actualWidth = $tip[0].offsetWidth;\n\t\t\tvar actualHeight = $tip[0].offsetHeight;\n\n\t\t\tif (autoPlace) {\n\t\t\t\tvar orgPlacement = placement;\n\t\t\t\tvar $container = this.options.container ? $(this.options.container) : this.$element.parent();\n\t\t\t\tvar containerDim = this.getPosition($container);\n\n\t\t\t\tplacement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top': placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom': placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left': placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right': placement\n\t\t\t\t$tip.removeClass(orgPlacement).addClass(placement);\n\t\t\t}\n\n\t\t\tvar calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight);\n\t\t\tthis.applyPlacement(calculatedOffset, placement);\n\t\t\tvar complete = function() {\n\t\t\t\tvar prevHoverState = that.hoverState;\n\t\t\t\tthat.$element.trigger('shown.bs.' + that.type);\n\t\t\t\tthat.hoverState = null;\n\t\t\t\tif (prevHoverState == 'out') that.leave(that);\n\t\t\t}\n\n\t\t\t$.support.transition && this.$tip.hasClass('fade') ? $tip.one('bsTransitionEnd', complete).emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : complete()\n\t\t}\n\t}\n\n\tTooltip.prototype.applyPlacement = function(offset, placement) {\n\t\tvar $tip = this.tip();\n\t\tvar width = $tip[0].offsetWidth;\n\t\tvar height = $tip[0].offsetHeight;\n\n\t\t// manually read margins because getBoundingClientRect includes difference\n\t\tvar marginTop = parseInt($tip.css('margin-top'), 10);\n\t\tvar marginLeft = parseInt($tip.css('margin-left'), 10);\n\n\t\t// we must check for NaN for ie 8/9\n\t\tif (isNaN(marginTop)) marginTop = 0;\n\t\tif (isNaN(marginLeft)) marginLeft = 0;\n\n\t\toffset.top = offset.top + marginTop;\n\t\toffset.left = offset.left + marginLeft;\n\n\t\t// $.fn.offset doesn't round pixel values\n\t\t// so we use setOffset directly with our own function B-0\n\t\t$.offset.setOffset($tip[0], $.extend({\n\t\t\tusing: function(props) {\n\t\t\t\t$tip.css({\n\t\t\t\t\ttop: Math.round(props.top),\n\t\t\t\t\tleft: Math.round(props.left)\n\t\t\t\t})\n\t\t\t}\n\t\t},\n\t\toffset), 0);\n\n\t\t$tip.addClass('in');\n\n\t\t// check to see if placing tip in new offset caused the tip to resize itself\n\t\tvar actualWidth = $tip[0].offsetWidth;\n\t\tvar actualHeight = $tip[0].offsetHeight;\n\n\t\tif (placement == 'top' && actualHeight != height) {\n\t\t\toffset.top = offset.top + height - actualHeight;\n\t\t}\n\n\t\tvar delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight);\n\n\t\tif (delta.left) offset.left += delta.left;\n\t\telse offset.top += delta.top;\n\n\t\tvar isVertical = /top|bottom/.test(placement);\n\t\tvar arrowDelta = isVertical ? delta.left * 2 - width + actualWidth: delta.top * 2 - height + actualHeight;\n\t\tvar arrowOffsetPosition = isVertical ? 'offsetWidth': 'offsetHeight';\n\n\t\t$tip.offset(offset);\n\t\tthis.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical);\n\t}\n\n\tTooltip.prototype.replaceArrow = function(delta, dimension, isHorizontal) {\n\t\tthis.arrow().css(isHorizontal ? 'left': 'top', 50 * (1 - delta / dimension) + '%').css(isHorizontal ? 'top': 'left', '');\n\t}\n\n\tTooltip.prototype.setContent = function() {\n\t\tvar $tip = this.tip();\n\t\tvar title = this.getTitle();\n\t\t$tip.find('.tooltip-inner')[this.options.html ? 'html': 'text'](title);\n\t\t$tip.removeClass('fade in top bottom left right');\n\t}\n\n\tTooltip.prototype.hide = function(callback) {\n\t\tvar that = this;\n\t\tvar $tip = this.tip();\n\t\tvar e = $.Event('hide.bs.' + this.type);\n\t\tfunction complete() {\n\t\t\tif (that.hoverState != 'in') $tip.detach();\n\t\t\tthat.$element.removeAttr('aria-describedby').trigger('hidden.bs.' + that.type);\n\t\t\tcallback && callback();\n\t\t}\n\t\tthis.$element.trigger(e);\n\t\tif (e.isDefaultPrevented()) return;\n\t\t$tip.removeClass('in');\n\n\t\t$.support.transition && this.$tip.hasClass('fade') ? $tip.one('bsTransitionEnd', complete).emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : complete();\n\t\tthis.hoverState = null;\n\t\treturn this;\n\t}\n\n\tTooltip.prototype.fixTitle = function() {\n\t\tvar $e = this.$element\n\t\tif ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {\n\t\t\t$e.attr('data-original-title', $e.attr('title') || '').attr('title', '')\n\t\t}\n\t}\n\n\tTooltip.prototype.hasContent = function() {\n\t\treturn this.getTitle();\n\t}\n\n\tTooltip.prototype.getPosition = function($element) {\n\t\t$element = $element || this.$element;\n\t\tvar el = $element[0];\n\t\tvar isBody = el.tagName == 'BODY';\n\t\tvar elRect = el.getBoundingClientRect();\n\t\tif (elRect.width == null) {\n\t\t\t// width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n\t\t\telRect = $.extend({},\n\t\t\telRect, {\n\t\t\t\twidth: elRect.right - elRect.left,\n\t\t\t\theight: elRect.bottom - elRect.top\n\t\t\t});\n\t\t}\n\t\tvar elOffset = isBody ? {\n\t\t\ttop: 0,\n\t\t\tleft: 0\n\t\t}: $element.offset();\n\t\tvar scroll = {\n\t\t\tscroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop: $element.scrollTop()\n\t\t}\n\t\tvar outerDims = isBody ? {\n\t\t\twidth: $(window).width(),\n\t\t\theight: $(window).height()\n\t\t}: null\n\t\treturn $.extend({},\n\t\telRect, scroll, outerDims, elOffset)\n\t}\n\n\tTooltip.prototype.getCalculatedOffset = function(placement, pos, actualWidth, actualHeight) {\n\t\treturn placement == 'bottom' ? {\n\t\t\ttop: pos.top + pos.height,\n\t\t\tleft: pos.left + pos.width / 2 - actualWidth / 2\n\t\t}: placement == 'top' ? {\n\t\t\ttop: pos.top - actualHeight,\n\t\t\tleft: pos.left + pos.width / 2 - actualWidth / 2\n\t\t}: placement == 'left' ? {\n\t\t\ttop: pos.top + pos.height / 2 - actualHeight / 2,\n\t\t\tleft: pos.left - actualWidth\n\t\t}:\n\t\t/* placement == 'right' */\n\t\t{\n\t\t\ttop: pos.top + pos.height / 2 - actualHeight / 2,\n\t\t\tleft: pos.left + pos.width\n\t\t}\n\n\t}\n\n\tTooltip.prototype.getViewportAdjustedDelta = function(placement, pos, actualWidth, actualHeight) {\n\t\tvar delta = {\n\t\t\ttop: 0,\n\t\t\tleft: 0\n\t\t}\n\t\tif (!this.$viewport) return delta;\n\n\t\tvar viewportPadding = this.options.viewport && this.options.viewport.padding || 0;\n\t\tvar viewportDimensions = this.getPosition(this.$viewport);\n\n\t\tif (/right|left/.test(placement)) {\n\t\t\tvar topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll;\n\t\t\tvar bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight;\n\t\t\tif (topEdgeOffset < viewportDimensions.top) { // top overflow\n\t\t\t\tdelta.top = viewportDimensions.top - topEdgeOffset;\n\t\t\t} else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n\t\t\t\tdelta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset;\n\t\t\t}\n\t\t} else {\n\t\t\tvar leftEdgeOffset = pos.left - viewportPadding;\n\t\t\tvar rightEdgeOffset = pos.left + viewportPadding + actualWidth;\n\t\t\tif (leftEdgeOffset < viewportDimensions.left) { // left overflow\n\t\t\t\tdelta.left = viewportDimensions.left - leftEdgeOffset;\n\t\t\t} else if (rightEdgeOffset > viewportDimensions.width) { // right overflow\n\t\t\t\tdelta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset;\n\t\t\t}\n\t\t}\n\t\treturn delta\n\t}\n\n\tTooltip.prototype.getTitle = function() {\n\t\tvar title;\n\t\tvar $e = this.$element;\n\t\tvar o = this.options;\n\t\ttitle = $e.attr('data-original-title') || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)\n\t\treturn title;\n\t}\n\n\tTooltip.prototype.getUID = function(prefix) {\n\t\tdo prefix += ~~ (Math.random() * 1000000);\n\t\twhile (document.getElementById(prefix));\n\t\treturn prefix;\n\t}\n\n\tTooltip.prototype.tip = function() {\n\t\treturn (this.$tip = this.$tip || $(this.options.template));\n\t}\n\n\tTooltip.prototype.arrow = function() {\n\t\treturn (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'));\n\t}\n\n\tTooltip.prototype.enable = function() {\n\t\tthis.enabled = true;\n\t}\n\n\tTooltip.prototype.disable = function() {\n\t\tthis.enabled = false;\n\t}\n\n\tTooltip.prototype.toggleEnabled = function() {\n\t\tthis.enabled = !this.enabled;\n\t}\n\n\tTooltip.prototype.toggle = function(e) {\n\t\tvar self = this;\n\t\tif (e) {\n\t\t\tself = $(e.currentTarget).data('bs.' + this.type);\n\t\t\tif (!self) {\n\t\t\t\tself = new this.constructor(e.currentTarget, this.getDelegateOptions());\n\t\t\t\t$(e.currentTarget).data('bs.' + this.type, self);\n\t\t\t}\n\t\t}\n\t\tself.tip().hasClass('in') ? self.leave(self) : self.enter(self)\n\t}\n\n\tTooltip.prototype.destroy = function() {\n\t\tvar that = this;\n\t\tclearTimeout(this.timeout);\n\t\tthis.hide(function() {\n\t\t\tthat.$element.off('.' + that.type).removeData('bs.' + that.type);\n\t\t});\n\t}\n\n\t// TOOLTIP PLUGIN DEFINITION\n\t// =========================\n\tfunction Plugin(option) {\n\t\treturn this.each(function() {\n\t\t\tvar $this = $(this);\n\t\t\tvar data = $this.data('bs.tooltip');\n\t\t\tvar options = typeof option == 'object' && option;\n\t\t\tvar selector = options && options.selector;\n\n\t\t\tif (!data && option == 'destroy') return;\n\t\t\tif (selector) {\n\t\t\t\tif (!data) $this.data('bs.tooltip', (data = {}));\n\t\t\t\tif (!data[selector]) data[selector] = new Tooltip(this, options);\n\t\t\t} else {\n\t\t\t\tif (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)));\n\t\t\t}\n\t\t\tif (typeof option == 'string') data[option]()\n\t\t})\n\t}\n\n\tvar old = $.fn.tooltip;\n\t$.fn.tooltip = Plugin;\n\t$.fn.tooltip.Constructor = Tooltip;\n\t// TOOLTIP NO CONFLICT\n\t// ===================\n\t$.fn.tooltip.noConflict = function() {\n\t\t$.fn.tooltip = old;\n\t\treturn this;\n\t}\n} (window.jQuery);\n$(function() {\n\t$(\"[data-toggle='tooltip']\").tooltip();\n});\n\n/* =======================================================================\n * Bootstrap.popover.js v3.3.0\n * http://getbootstrap.com/javascript/#popovers\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n!\nfunction($) {\n\t'use strict';\n\t// POPOVER PUBLIC CLASS DEFINITION\n\t// ===============================\t\n\tvar Popover = function(element, options) {\n\t\tthis.init('popover', element, options)\n\t}\n\n\tif (!$.fn.tooltip) throw new Error('Popover requires tooltip.js');\n\tPopover.VERSION = '3.3.0';\n\tPopover.DEFAULTS = $.extend({},\n\t$.fn.tooltip.Constructor.DEFAULTS, {\n\t\tplacement: 'right',\n\t\ttrigger: 'click',\n\t\tcontent: '',\n\t\ttemplate: '<div class=\"popover\" role=\"tooltip\"><div class=\"arrow\"></div><h3 class=\"popover-title\"></h3><div class=\"popover-content\"></div></div>'\n\t})\n\n\t// NOTE: POPOVER EXTENDS tooltip.js\n\t// ================================\t\n\tPopover.prototype = $.extend({},$.fn.tooltip.Constructor.prototype);\n\tPopover.prototype.constructor = Popover;\n\tPopover.prototype.getDefaults = function() {\n\t\treturn Popover.DEFAULTS;\n\t}\n\n\tPopover.prototype.setContent = function() {\n\t\tvar $tip = this.tip();\n\t\tvar title = this.getTitle();\n\t\tvar content = this.getContent();\n\n\t\t$tip.find('.popover-title')[this.options.html ? 'html': 'text'](title);\n\t\t$tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events\n\t\t\tthis.options.html ? (typeof content == 'string' ? 'html': 'append') : 'text'](content)\n\n\t\t$tip.removeClass('fade top bottom left right in');\n\n\t\t// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do\n\t\t// this manually by checking the contents.\n\t\tif (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide();\n\t}\n\n\tPopover.prototype.hasContent = function() {\n\t\treturn this.getTitle() || this.getContent()\n\t}\n\n\tPopover.prototype.getContent = function() {\n\t\tvar $e = this.$element;\n\t\tvar o = this.options;\n\n\t\treturn $e.attr('data-content') || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)\n\t}\n\n\tPopover.prototype.arrow = function() {\n\t\treturn (this.$arrow = this.$arrow || this.tip().find('.arrow'))\n\t}\n\n\tPopover.prototype.tip = function() {\n\t\tif (!this.$tip) this.$tip = $(this.options.template);\n\t\treturn this.$tip;\n\t}\n\n\t// POPOVER PLUGIN DEFINITION\n\t// =========================\t\n\tfunction Plugin(option) {\n\t\treturn this.each(function() {\n\t\t\tvar $this = $(this);\n\t\t\tvar data = $this.data('bs.popover');\n\t\t\tvar options = typeof option == 'object' && option;\n\t\t\tvar selector = options && options.selector;\n\n\t\t\tif (!data && option == 'destroy') return;\n\t\t\tif (selector) {\n\t\t\t\tif (!data) $this.data('bs.popover', (data = {}));\n\t\t\t\tif (!data[selector]) data[selector] = new Popover(this, options);\n\t\t\t} else {\n\t\t\t\tif (!data) $this.data('bs.popover', (data = new Popover(this, options)))\n\t\t\t}\n\t\t\tif (typeof option == 'string') data[option]()\n\t\t})\n\t}\n\n\tvar old = $.fn.popover\n\n\t$.fn.popover = Plugin;\n\t$.fn.popover.Constructor = Popover;\n\n\t// POPOVER NO CONFLICT\n\t// ===================\n\t$.fn.popover.noConflict = function() {\n\t\t$.fn.popover = old;\n\t\treturn this;\n\t}\n} (window.jQuery);\n$(function() {\n\t$(\"[data-toggle='popover']\").popover();\n});\n\n/* =======================================================================\n * Bootstrap.alert.js v3.3.0\n * http://getbootstrap.com/javascript/#alerts\n * ========================================================================\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n!function($) {\n\t'use strict';\n\t// ALERT CLASS DEFINITION\n\t// ======================\n\tvar dismiss = '[data-dismiss=\"alert\"]'\n\tvar Alert = function(el) {\n\t\t$(el).on('click', dismiss, this.close)\n\t}\n\n\tAlert.VERSION = '3.3.0'\n\n\tAlert.TRANSITION_DURATION = 150\n\n\tAlert.prototype.close = function(e) {\n\t\tvar $this = $(this);\n\t\tvar selector = $this.attr('data-target');\n\n\t\tif (!selector) {\n\t\t\tselector = $this.attr('href');\n\t\t\tselector = selector && selector.replace(/.*(?=#[^\\s]*$)/, ''); // strip for ie7\n\t\t}\n\n\t\tvar $parent = $(selector);\n\t\tif (e) e.preventDefault();\n\t\tif (!$parent.length) {\n\t\t\t$parent = $this.closest('.alert');\n\t\t}\n\n\t\t$parent.trigger(e = $.Event('close.bs.alert'))\n\n\t\tif (e.isDefaultPrevented()) return;\n\n\t\t$parent.removeClass('in');\n\t\tfunction removeElement() {\n\t\t\t// detach from parent, fire event then clean up data\n\t\t\t$parent.detach().trigger('closed.bs.alert').remove();\n\t\t}\n\n\t\t$.support.transition && $parent.hasClass('fade') ? $parent.one('bsTransitionEnd', removeElement).emulateTransitionEnd(Alert.TRANSITION_DURATION) : removeElement()\n\t}\n\n\t// ALERT PLUGIN DEFINITION\n\t// =======================\n\tfunction Plugin(option) {\n\t\treturn this.each(function() {\n\t\t\tvar $this = $(this);\n\t\t\tvar data = $this.data('bs.alert');\n\t\t\tif (!data) $this.data('bs.alert', (data = new Alert(this)));\n\t\t\tif (typeof option == 'string') data[option].call($this);\n\t\t})\n\t}\n\n\tvar old = $.fn.alert;\n\t$.fn.alert = Plugin;\n\t$.fn.alert.Constructor = Alert;\n\n\t// ALERT NO CONFLICT\n\t// =================\t\n\t$.fn.alert.noConflict = function() {\n\t\t$.fn.alert = old;\n\t\treturn this;\n\t}\n\t// ALERT DATA-API\n\t// ==============\n\t$(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)\n} (window.jQuery);\n\n/* =========================================================\n * Bootstrap.slider.js v1.0.1\n * Maintainers:\n *\t\tKyle Kemp\n *\t\t\t- Twitter: @seiyria\n *\t\t\t- Github:  seiyria\n *\t\tRohit Kalkur\n *\t\t\t- Twitter: @Rovolutionary\n *\t\t\t- Github:  rovolution\n *\n * =========================================================\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 * Bridget makes jQuery widgets\n * MIT license\n * ========================================================= */\n(function(root, factory) {\n\tif (typeof define === \"function\" && define.amd) {\n\t\tdefine([\"jquery\"], factory);\n\t} else if (typeof module === \"object\" && module.exports) {\n\t\tvar jQuery;\n\t\ttry {\n\t\t\tjQuery = require(\"jquery\");\n\t\t} catch(err) {\n\t\t\tjQuery = null;\n\t\t}\n\t\tmodule.exports = factory(jQuery);\n\t} else {\n\t\troot.Slider = factory(root.jQuery);\n\t}\n} (this,\nfunction($) {\n\t// Reference to Slider constructor\n\tvar Slider; (function($) {\n\t\t'use strict';\n\t\t// -------------------------- utils -------------------------- //\n\t\tvar slice = Array.prototype.slice;\n\t\tfunction noop() {}\n\t\t// -------------------------- definition -------------------------- //\n\t\tfunction defineBridget($) {\n\t\t\t// bail if no jQuery\n\t\t\tif (!$) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// -------------------------- addOptionMethod -------------------------- //\n\t\t\t/**\n\t\t\t * adds option method -> $().plugin('option', {...})\n\t\t\t * @param {Function} PluginClass - constructor class\n\t\t\t */\n\t\t\tfunction addOptionMethod(PluginClass) {\n\t\t\t\t// don't overwrite original option method\n\t\t\t\tif (PluginClass.prototype.option) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// option setter\n\t\t\t\tPluginClass.prototype.option = function(opts) {\n\t\t\t\t\t// bail out if not an object\n\t\t\t\t\tif (!$.isPlainObject(opts)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis.options = $.extend(true, this.options, opts);\n\t\t\t\t};\n\t\t\t}\n\t\t\t// -------------------------- plugin bridge -------------------------- //\n\t\t\t// helper function for logging errors\n\t\t\t// $.error breaks jQuery chaining\n\t\t\tvar logError = typeof console === 'undefined' ? noop: function(message) {\n\t\t\t\tconsole.error(message);\n\t\t\t};\n\t\t\t/**\n\t\t\t * jQuery plugin bridge, access methods like $elem.plugin('method')\n\t\t\t * @param {String} namespace - plugin name\n\t\t\t * @param {Function} PluginClass - constructor class\n\t\t\t*/\n\t\t\tfunction bridge(namespace, PluginClass) {\n\t\t\t\t// add to jQuery fn namespace\n\t\t\t\t$.fn[namespace] = function(options) {\n\t\t\t\t\tif (typeof options === 'string') {\n\t\t\t\t\t\t// call plugin method when first argument is a string\n\t\t\t\t\t\t// get arguments for method\n\t\t\t\t\t\tvar args = slice.call(arguments, 1);\n\t\t\t\t\t\tfor (var i = 0,\n\t\t\t\t\t\tlen = this.length; i < len; i++) {\n\t\t\t\t\t\t\tvar elem = this[i];\n\t\t\t\t\t\t\tvar instance = $.data(elem, namespace);\n\t\t\t\t\t\t\tif (!instance) {\n\t\t\t\t\t\t\t\tlogError(\"cannot call methods on \" + namespace + \" prior to initialization; \" + \"attempted to call '\" + options + \"'\");\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!$.isFunction(instance[options]) || options.charAt(0) === '_') {\n\t\t\t\t\t\t\t\tlogError(\"no such method '\" + options + \"' for \" + namespace + \" instance\");\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// trigger method with arguments\n\t\t\t\t\t\t\tvar returnValue = instance[options].apply(instance, args);\n\n\t\t\t\t\t\t\t// break look and return first value if provided\n\t\t\t\t\t\t\tif (returnValue !== undefined && returnValue !== instance) {\n\t\t\t\t\t\t\t\treturn returnValue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// return this if no return value\n\t\t\t\t\t\treturn this;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar objects = this.map(function() {\n\t\t\t\t\t\t\tvar instance = $.data(this, namespace);\n\t\t\t\t\t\t\tif (instance) {\n\t\t\t\t\t\t\t\t// apply options & init\n\t\t\t\t\t\t\t\tinstance.option(options);\n\t\t\t\t\t\t\t\tinstance._init();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// initialize new instance\n\t\t\t\t\t\t\t\tinstance = new PluginClass(this, options);\n\t\t\t\t\t\t\t\t$.data(this, namespace, instance);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn $(this);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!objects || objects.length > 1) {\n\t\t\t\t\t\t\treturn objects;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn objects[0];\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\t// -------------------------- bridget -------------------------- //\n\t\t\t/**\n\t\t\t * converts a Prototypical class into a proper jQuery plugin\n\t\t\t *   the class must have a ._init method\n\t\t\t * @param {String} namespace - plugin name, used in $().pluginName\n\t\t\t * @param {Function} PluginClass - constructor class\n\t\t\t */\n\t\t\t$.bridget = function(namespace, PluginClass) {\n\t\t\t\taddOptionMethod(PluginClass);\n\t\t\t\tbridge(namespace, PluginClass);\n\t\t\t};\n\t\t\treturn $.bridget;\n\t\t}\n\n\t\t// get jquery from browser global\n\t\tdefineBridget($);\n\t})($);\n\t/*************************************************\n\t\t\tBOOTSTRAP-SLIDER SOURCE CODE\n\t**************************************************/\n\t(function($) {\n\t\tvar ErrorMsgs = {\n\t\t\tformatInvalidInputErrorMsg: function(input) {\n\t\t\t\treturn \"Invalid input value '\" + input + \"' passed in\";\n\t\t\t},\n\t\t\tcallingContextNotSliderInstance: \"Calling context element does not have instance of Slider bound to it. Check your code to make sure the JQuery object returned from the call to the slider() initializer is calling the method\"\n\t\t};\n\n\t\t/*************************************************\n\t\t\t\t\t\t\tCONSTRUCTOR\n\t\t**************************************************/\n\t\tSlider = function(element, options) {\n\t\t\tcreateNewSlider.call(this, element, options);\n\t\t\treturn this;\n\t\t};\n\t\tfunction createNewSlider(element, options) {\n\t\t\t/*************************************************\n\t\t\t\t\t\t\tCreate Markup\n\t\t\t**************************************************/\n\t\t\tif (typeof element === \"string\") {\n\t\t\t\tthis.element = document.querySelector(element);\n\t\t\t} else if (element instanceof HTMLElement) {\n\t\t\t\tthis.element = element;\n\t\t\t}\n\n\t\t\tvar origWidth = this.element.style.width;\n\t\t\tvar updateSlider = false;\n\t\t\tvar parent = this.element.parentNode;\n\t\t\tvar sliderTrackSelection;\n\t\t\tvar sliderMinHandle;\n\t\t\tvar sliderMaxHandle;\n\n\t\t\tif (this.sliderElem) {\n\t\t\t\tupdateSlider = true;\n\t\t\t} else {\n\t\t\t\t/* Create elements needed for slider */\n\t\t\t\tthis.sliderElem = document.createElement(\"div\");\n\t\t\t\tthis.sliderElem.className = \"slider\";\n\n\t\t\t\t/* Create slider track elements */\n\t\t\t\tvar sliderTrack = document.createElement(\"div\");\n\t\t\t\tsliderTrack.className = \"slider-track\";\n\n\t\t\t\tsliderTrackSelection = document.createElement(\"div\");\n\t\t\t\tsliderTrackSelection.className = \"slider-selection\";\n\n\t\t\t\tsliderMinHandle = document.createElement(\"div\");\n\t\t\t\tsliderMinHandle.className = \"slider-handle min-slider-handle\";\n\n\t\t\t\tsliderMaxHandle = document.createElement(\"div\");\n\t\t\t\tsliderMaxHandle.className = \"slider-handle max-slider-handle\";\n\n\t\t\t\tsliderTrack.appendChild(sliderTrackSelection);\n\t\t\t\tsliderTrack.appendChild(sliderMinHandle);\n\t\t\t\tsliderTrack.appendChild(sliderMaxHandle);\n\n\t\t\t\tvar createAndAppendTooltipSubElements = function(tooltipElem) {\n\t\t\t\t\tvar arrow = document.createElement(\"div\");\n\t\t\t\t\tarrow.className = \"tooltip-arrow\";\n\n\t\t\t\t\tvar inner = document.createElement(\"div\");\n\t\t\t\t\tinner.className = \"tooltip-inner\";\n\n\t\t\t\t\ttooltipElem.appendChild(arrow);\n\t\t\t\t\ttooltipElem.appendChild(inner);\n\t\t\t\t};\n\n\t\t\t\t/* Create tooltip elements */\n\t\t\t\tvar sliderTooltip = document.createElement(\"div\");\n\t\t\t\tsliderTooltip.className = \"tooltip tooltip-main\";\n\t\t\t\tcreateAndAppendTooltipSubElements(sliderTooltip);\n\n\t\t\t\tvar sliderTooltipMin = document.createElement(\"div\");\n\t\t\t\tsliderTooltipMin.className = \"tooltip tooltip-min\";\n\t\t\t\tcreateAndAppendTooltipSubElements(sliderTooltipMin);\n\n\t\t\t\tvar sliderTooltipMax = document.createElement(\"div\");\n\t\t\t\tsliderTooltipMax.className = \"tooltip tooltip-max\";\n\t\t\t\tcreateAndAppendTooltipSubElements(sliderTooltipMax);\n\n\t\t\t\t/* Append components to sliderElem */\n\t\t\t\tthis.sliderElem.appendChild(sliderTrack);\n\t\t\t\tthis.sliderElem.appendChild(sliderTooltip);\n\t\t\t\tthis.sliderElem.appendChild(sliderTooltipMin);\n\t\t\t\tthis.sliderElem.appendChild(sliderTooltipMax);\n\n\t\t\t\t/* Append slider element to parent container, right before the original <input> element */\n\t\t\t\tparent.insertBefore(this.sliderElem, this.element);\n\n\t\t\t\t/* Hide original <input> element */\n\t\t\t\tthis.element.style.display = \"none\";\n\t\t\t}\n\t\t\t/* If JQuery exists, cache JQ references */\n\t\t\tif ($) {\n\t\t\t\tthis.$element = $(this.element);\n\t\t\t\tthis.$sliderElem = $(this.sliderElem);\n\t\t\t}\n\n\t\t\t/*************************************************\n\t\t\t\t\t\t\tProcess Options\n\t\t\t**************************************************/\n\t\t\toptions = options ? options: {};\n\t\t\tvar optionTypes = Object.keys(this.defaultOptions);\n\n\t\t\tfor (var i = 0; i < optionTypes.length; i++) {\n\t\t\t\tvar optName = optionTypes[i];\n\n\t\t\t\t// First check if an option was passed in via the constructor\n\t\t\t\tvar val = options[optName];\n\t\t\t\t// If no data attrib, then check data atrributes\n\t\t\t\tval = (typeof val !== 'undefined') ? val : getDataAttrib(this.element, optName);\n\t\t\t\t// Finally, if nothing was specified, use the defaults\n\t\t\t\tval = (val !== null) ? val : this.defaultOptions[optName];\n\n\t\t\t\t// Set all options on the instance of the Slider\n\t\t\t\tif (!this.options) {\n\t\t\t\t\tthis.options = {};\n\t\t\t\t}\n\t\t\t\tthis.options[optName] = val;\n\t\t\t}\n\n\t\t\tfunction getDataAttrib(element, optName) {\n\t\t\t\tvar dataName = \"data-slider-\" + optName;\n\t\t\t\tvar dataValString = element.getAttribute(dataName);\n\n\t\t\t\ttry {\n\t\t\t\t\treturn JSON.parse(dataValString);\n\t\t\t\t} catch(err) {\n\t\t\t\t\treturn dataValString;\n\t\t\t\t}\n\t\t\t}\n\t\t\t/*************************************************\n\t\t\t\t\t\t\t\tSetup\n\t\t\t**************************************************/\n\t\t\tthis.eventToCallbackMap = {};\n\t\t\tthis.sliderElem.id = this.options.id;\n\n\t\t\tthis.touchCapable = 'ontouchstart' in window || (window.DocumentTouch && document instanceof window.DocumentTouch);\n\n\t\t\tthis.tooltip = this.sliderElem.querySelector('.tooltip-main');\n\t\t\tthis.tooltipInner = this.tooltip.querySelector('.tooltip-inner');\n\n\t\t\tthis.tooltip_min = this.sliderElem.querySelector('.tooltip-min');\n\t\t\tthis.tooltipInner_min = this.tooltip_min.querySelector('.tooltip-inner');\n\n\t\t\tthis.tooltip_max = this.sliderElem.querySelector('.tooltip-max');\n\t\t\tthis.tooltipInner_max = this.tooltip_max.querySelector('.tooltip-inner');\n\n\t\t\tif (updateSlider === true) {\n\t\t\t\t// Reset classes\n\t\t\t\tthis._removeClass(this.sliderElem, 'slider-horizontal');\n\t\t\t\tthis._removeClass(this.sliderElem, 'slider-vertical');\n\t\t\t\tthis._removeClass(this.tooltip, 'hide');\n\t\t\t\tthis._removeClass(this.tooltip_min, 'hide');\n\t\t\t\tthis._removeClass(this.tooltip_max, 'hide');\n\n\t\t\t\t// Undo existing inline styles for track\n\t\t\t\t[\"left\", \"top\", \"width\", \"height\"].forEach(function(prop) {\n\t\t\t\t\tthis._removeProperty(this.trackSelection, prop);\n\t\t\t\t},\n\t\t\t\tthis);\n\n\t\t\t\t// Undo inline styles on handles\n\t\t\t\t[this.handle1, this.handle2].forEach(function(handle) {\n\t\t\t\t\tthis._removeProperty(handle, 'left');\n\t\t\t\t\tthis._removeProperty(handle, 'top');\n\t\t\t\t},\n\t\t\t\tthis);\n\n\t\t\t\t// Undo inline styles and classes on tooltips\n\t\t\t\t[this.tooltip, this.tooltip_min, this.tooltip_max].forEach(function(tooltip) {\n\t\t\t\t\tthis._removeProperty(tooltip, 'left');\n\t\t\t\t\tthis._removeProperty(tooltip, 'top');\n\t\t\t\t\tthis._removeProperty(tooltip, 'margin-left');\n\t\t\t\t\tthis._removeProperty(tooltip, 'margin-top');\n\n\t\t\t\t\tthis._removeClass(tooltip, 'right');\n\t\t\t\t\tthis._removeClass(tooltip, 'top');\n\t\t\t\t},\n\t\t\t\tthis);\n\t\t\t}\n\n\t\t\tif (this.options.orientation === 'vertical') {\n\t\t\t\tthis._addClass(this.sliderElem, 'slider-vertical');\n\n\t\t\t\tthis.stylePos = 'top';\n\t\t\t\tthis.mousePos = 'pageY';\n\t\t\t\tthis.sizePos = 'offsetHeight';\n\n\t\t\t\tthis._addClass(this.tooltip, 'right');\n\t\t\t\tthis.tooltip.style.left = '100%';\n\n\t\t\t\tthis._addClass(this.tooltip_min, 'right');\n\t\t\t\tthis.tooltip_min.style.left = '100%';\n\n\t\t\t\tthis._addClass(this.tooltip_max, 'right');\n\t\t\t\tthis.tooltip_max.style.left = '100%';\n\t\t\t} else {\n\t\t\t\tthis._addClass(this.sliderElem, 'slider-horizontal');\n\t\t\t\tthis.sliderElem.style.width = origWidth;\n\n\t\t\t\tthis.options.orientation = 'horizontal';\n\t\t\t\tthis.stylePos = 'left';\n\t\t\t\tthis.mousePos = 'pageX';\n\t\t\t\tthis.sizePos = 'offsetWidth';\n\n\t\t\t\tthis._addClass(this.tooltip, 'top');\n\t\t\t\tthis.tooltip.style.top = -this.tooltip.outerHeight - 14 + 'px';\n\n\t\t\t\tthis._addClass(this.tooltip_min, 'top');\n\t\t\t\tthis.tooltip_min.style.top = -this.tooltip_min.outerHeight - 14 + 'px';\n\n\t\t\t\tthis._addClass(this.tooltip_max, 'top');\n\t\t\t\tthis.tooltip_max.style.top = -this.tooltip_max.outerHeight - 14 + 'px';\n\t\t\t}\n\n\t\t\tif (this.options.value instanceof Array) {\n\t\t\t\tthis.options.range = true;\n\t\t\t} else if (this.options.range) {\n\t\t\t\t// User wants a range, but value is not an array\n\t\t\t\tthis.options.value = [this.options.value, this.options.max];\n\t\t\t}\n\n\t\t\tthis.trackSelection = sliderTrackSelection || this.trackSelection;\n\t\t\tif (this.options.selection === 'none') {\n\t\t\t\tthis._addClass(this.trackSelection, 'hide');\n\t\t\t}\n\n\t\t\tthis.handle1 = sliderMinHandle || this.handle1;\n\t\t\tthis.handle2 = sliderMaxHandle || this.handle2;\n\n\t\t\tif (updateSlider === true) {\n\t\t\t\t// Reset classes\n\t\t\t\tthis._removeClass(this.handle1, 'round triangle');\n\t\t\t\tthis._removeClass(this.handle2, 'round triangle hide');\n\t\t\t}\n\n\t\t\tvar availableHandleModifiers = ['round', 'triangle', 'custom'];\n\t\t\tvar isValidHandleType = availableHandleModifiers.indexOf(this.options.handle) !== -1;\n\t\t\tif (isValidHandleType) {\n\t\t\t\tthis._addClass(this.handle1, this.options.handle);\n\t\t\t\tthis._addClass(this.handle2, this.options.handle);\n\t\t\t}\n\n\t\t\tthis.offset = this._offset(this.sliderElem);\n\t\t\tthis.size = this.sliderElem[this.sizePos];\n\t\t\tthis.setValue(this.options.value);\n\n\t\t\t/******************************************\n\t\t\t\t\t\tBind Event Listeners\n\t\t\t******************************************/\n\t\t\t// Bind keyboard handlers\n\t\t\tthis.handle1Keydown = this._keydown.bind(this, 0);\n\t\t\tthis.handle1.addEventListener(\"keydown\", this.handle1Keydown, false);\n\n\t\t\tthis.handle2Keydown = this._keydown.bind(this, 1);\n\t\t\tthis.handle2.addEventListener(\"keydown\", this.handle2Keydown, false);\n\n\t\t\tif (this.touchCapable) {\n\t\t\t\t// Bind touch handlers\n\t\t\t\tthis.mousedown = this._mousedown.bind(this);\n\t\t\t\tthis.sliderElem.addEventListener(\"touchstart\", this.mousedown, false);\n\t\t\t} else {\n\t\t\t\t// Bind mouse handlers\n\t\t\t\tthis.mousedown = this._mousedown.bind(this);\n\t\t\t\tthis.sliderElem.addEventListener(\"mousedown\", this.mousedown, false);\n\t\t\t}\n\n\t\t\t// Bind tooltip-related handlers\n\t\t\tif (this.options.tooltip === 'hide') {\n\t\t\t\tthis._addClass(this.tooltip, 'hide');\n\t\t\t\tthis._addClass(this.tooltip_min, 'hide');\n\t\t\t\tthis._addClass(this.tooltip_max, 'hide');\n\t\t\t} else if (this.options.tooltip === 'always') {\n\t\t\t\tthis._showTooltip();\n\t\t\t\tthis._alwaysShowTooltip = true;\n\t\t\t} else {\n\t\t\t\tthis.showTooltip = this._showTooltip.bind(this);\n\t\t\t\tthis.hideTooltip = this._hideTooltip.bind(this);\n\n\t\t\t\tthis.sliderElem.addEventListener(\"mouseenter\", this.showTooltip, false);\n\t\t\t\tthis.sliderElem.addEventListener(\"mouseleave\", this.hideTooltip, false);\n\n\t\t\t\tthis.handle1.addEventListener(\"focus\", this.showTooltip, false);\n\t\t\t\tthis.handle1.addEventListener(\"blur\", this.hideTooltip, false);\n\n\t\t\t\tthis.handle2.addEventListener(\"focus\", this.showTooltip, false);\n\t\t\t\tthis.handle2.addEventListener(\"blur\", this.hideTooltip, false);\n\t\t\t}\n\n\t\t\tif (this.options.enabled) {\n\t\t\t\tthis.enable();\n\t\t\t} else {\n\t\t\t\tthis.disable();\n\t\t\t}\n\t\t}\n\n\t\t/*************************************************\n\t\t\t\t\tINSTANCE PROPERTIES/METHODS\n\t\t- Any methods bound to the prototype are considered\n\t\tpart of the plugin's `public` interface\n\t\t**************************************************/\n\t\tSlider.prototype = {\n\t\t\t_init: function() {},\n\t\t\t// NOTE: Must exist to support bridget\n\t\t\tconstructor: Slider,\n\n\t\t\tdefaultOptions: {\n\t\t\t\tid: \"\",\n\t\t\t\tmin: 0,\n\t\t\t\tmax: 10,\n\t\t\t\tstep: 1,\n\t\t\t\tprecision: 0,\n\t\t\t\torientation: 'horizontal',\n\t\t\t\tvalue: 5,\n\t\t\t\trange: false,\n\t\t\t\tselection: 'before',\n\t\t\t\ttooltip: 'show',\n\t\t\t\ttooltip_split: false,\n\t\t\t\thandle: 'round',\n\t\t\t\treversed: false,\n\t\t\t\tenabled: true,\n\t\t\t\tformatter: function(val) {\n\t\t\t\t\tif (val instanceof Array) {\n\t\t\t\t\t\treturn val[0] + \" : \" + val[1];\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn val;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tnatural_arrow_keys: false\n\t\t\t},\n\n\t\t\tover: false,\n\n\t\t\tinDrag: false,\n\n\t\t\tgetValue: function() {\n\t\t\t\tif (this.options.range) {\n\t\t\t\t\treturn this.options.value;\n\t\t\t\t}\n\t\t\t\treturn this.options.value[0];\n\t\t\t},\n\n\t\t\tsetValue: function(val, triggerSlideEvent) {\n\t\t\t\tif (!val) {\n\t\t\t\t\tval = 0;\n\t\t\t\t}\n\t\t\t\tvar oldValue = this.getValue();\n\t\t\t\tthis.options.value = this._validateInputValue(val);\n\t\t\t\tvar applyPrecision = this._applyPrecision.bind(this);\n\n\t\t\t\tif (this.options.range) {\n\t\t\t\t\tthis.options.value[0] = applyPrecision(this.options.value[0]);\n\t\t\t\t\tthis.options.value[1] = applyPrecision(this.options.value[1]);\n\n\t\t\t\t\tthis.options.value[0] = Math.max(this.options.min, Math.min(this.options.max, this.options.value[0]));\n\t\t\t\t\tthis.options.value[1] = Math.max(this.options.min, Math.min(this.options.max, this.options.value[1]));\n\t\t\t\t} else {\n\t\t\t\t\tthis.options.value = applyPrecision(this.options.value);\n\t\t\t\t\tthis.options.value = [Math.max(this.options.min, Math.min(this.options.max, this.options.value))];\n\t\t\t\t\tthis._addClass(this.handle2, 'hide');\n\t\t\t\t\tif (this.options.selection === 'after') {\n\t\t\t\t\t\tthis.options.value[1] = this.options.max;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.options.value[1] = this.options.min;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis.diff = this.options.max - this.options.min;\n\t\t\t\tif (this.diff > 0) {\n\t\t\t\t\tthis.percentage = [\n\t\t\t\t\t\t(this.options.value[0] - this.options.min) * 100 / this.diff,\n\t\t\t\t\t\t(this.options.value[1] - this.options.min) * 100 / this.diff,\n\t\t\t\t\t\tthis.options.step * 100 / this.diff];\n\t\t\t\t} else {\n\t\t\t\t\tthis.percentage = [0, 0, 100];\n\t\t\t\t}\n\n\t\t\t\tthis._layout();\n\t\t\t\tvar newValue = this.options.range ? this.options.value : this.options.value[0];\n\n\t\t\t\tif (triggerSlideEvent === true) {\n\t\t\t\t\tthis._trigger('slide', newValue);\n\t\t\t\t}\n\t\t\t\tif (oldValue !== newValue) {\n\t\t\t\t\tthis._trigger('change', {\n\t\t\t\t\t\toldValue: oldValue,\n\t\t\t\t\t\tnewValue: newValue\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthis._setDataVal(newValue);\n\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\tdestroy: function() {\n\t\t\t\t// Remove event handlers on slider elements\n\t\t\t\tthis._removeSliderEventHandlers();\n\n\t\t\t\t// Remove the slider from the DOM\n\t\t\t\tthis.sliderElem.parentNode.removeChild(this.sliderElem);\n\t\t\t\t/* Show original <input> element */\n\t\t\t\tthis.element.style.display = \"\";\n\n\t\t\t\t// Clear out custom event bindings\n\t\t\t\tthis._cleanUpEventCallbacksMap();\n\n\t\t\t\t// Remove data values\n\t\t\t\tthis.element.removeAttribute(\"data\");\n\n\t\t\t\t// Remove JQuery handlers/data\n\t\t\t\tif ($) {\n\t\t\t\t\tthis._unbindJQueryEventHandlers();\n\t\t\t\t\tthis.$element.removeData('slider');\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tdisable: function() {\n\t\t\t\tthis.options.enabled = false;\n\t\t\t\tthis.handle1.removeAttribute(\"tabindex\");\n\t\t\t\tthis.handle2.removeAttribute(\"tabindex\");\n\t\t\t\tthis._addClass(this.sliderElem, 'slider-disabled');\n\t\t\t\tthis._trigger('slideDisabled');\n\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\tenable: function() {\n\t\t\t\tthis.options.enabled = true;\n\t\t\t\tthis.handle1.setAttribute(\"tabindex\", 0);\n\t\t\t\tthis.handle2.setAttribute(\"tabindex\", 0);\n\t\t\t\tthis._removeClass(this.sliderElem, 'slider-disabled');\n\t\t\t\tthis._trigger('slideEnabled');\n\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\ttoggle: function() {\n\t\t\t\tif (this.options.enabled) {\n\t\t\t\t\tthis.disable();\n\t\t\t\t} else {\n\t\t\t\t\tthis.enable();\n\t\t\t\t}\n\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\tisEnabled: function() {\n\t\t\t\treturn this.options.enabled;\n\t\t\t},\n\n\t\t\ton: function(evt, callback) {\n\t\t\t\tif ($) {\n\t\t\t\t\tthis.$element.on(evt, callback);\n\t\t\t\t\tthis.$sliderElem.on(evt, callback);\n\t\t\t\t} else {\n\t\t\t\t\tthis._bindNonQueryEventHandler(evt, callback);\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\tgetAttribute: function(attribute) {\n\t\t\t\tif (attribute) {\n\n\t\t\t\t\treturn this.options[attribute];\n\t\t\t\t} else {\n\t\t\t\t\treturn this.options;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tsetAttribute: function(attribute, value) {\n\t\t\t\tthis.options[attribute] = value;\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\trefresh: function() {\n\t\t\t\tthis._removeSliderEventHandlers();\n\t\t\t\tcreateNewSlider.call(this, this.element, this.options);\n\t\t\t\tif ($) {\n\t\t\t\t\t// Bind new instance of slider to the element\n\t\t\t\t\t$.data(this.element, 'slider', this);\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\trelayout: function() {\n\t\t\t\tthis._layout();\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t/******************************+\n\t\t\t\t\t\tHELPERS\n\t\t\t- Any method that is not part of the public interface.\n\t\t\t- Place it underneath this comment block and write its signature like so:\n\t\t\t  \t\t\t\t\t_fnName : function() {...}\n\t\t\t********************************/\n\t\t\t_removeSliderEventHandlers: function() {\n\t\t\t\t// Remove event listeners from handle1\n\t\t\t\tthis.handle1.removeEventListener(\"keydown\", this.handle1Keydown, false);\n\t\t\t\tthis.handle1.removeEventListener(\"focus\", this.showTooltip, false);\n\t\t\t\tthis.handle1.removeEventListener(\"blur\", this.hideTooltip, false);\n\n\t\t\t\t// Remove event listeners from handle2\n\t\t\t\tthis.handle2.removeEventListener(\"keydown\", this.handle2Keydown, false);\n\t\t\t\tthis.handle2.removeEventListener(\"focus\", this.handle2Keydown, false);\n\t\t\t\tthis.handle2.removeEventListener(\"blur\", this.handle2Keydown, false);\n\n\t\t\t\t// Remove event listeners from sliderElem\n\t\t\t\tthis.sliderElem.removeEventListener(\"mouseenter\", this.showTooltip, false);\n\t\t\t\tthis.sliderElem.removeEventListener(\"mouseleave\", this.hideTooltip, false);\n\t\t\t\tthis.sliderElem.removeEventListener(\"touchstart\", this.mousedown, false);\n\t\t\t\tthis.sliderElem.removeEventListener(\"mousedown\", this.mousedown, false);\n\t\t\t},\n\t\t\t_bindNonQueryEventHandler: function(evt, callback) {\n\t\t\t\tif (this.eventToCallbackMap[evt] === undefined) {\n\t\t\t\t\tthis.eventToCallbackMap[evt] = [];\n\t\t\t\t}\n\t\t\t\tthis.eventToCallbackMap[evt].push(callback);\n\t\t\t},\n\t\t\t_cleanUpEventCallbacksMap: function() {\n\t\t\t\tvar eventNames = Object.keys(this.eventToCallbackMap);\n\t\t\t\tfor (var i = 0; i < eventNames.length; i++) {\n\t\t\t\t\tvar eventName = eventNames[i];\n\t\t\t\t\tthis.eventToCallbackMap[eventName] = null;\n\t\t\t\t}\n\t\t\t},\n\t\t\t_showTooltip: function() {\n\t\t\t\tif (this.options.tooltip_split === false) {\n\t\t\t\t\tthis._addClass(this.tooltip, 'in');\n\t\t\t\t} else {\n\t\t\t\t\tthis._addClass(this.tooltip_min, 'in');\n\t\t\t\t\tthis._addClass(this.tooltip_max, 'in');\n\t\t\t\t}\n\t\t\t\tthis.over = true;\n\t\t\t},\n\t\t\t_hideTooltip: function() {\n\t\t\t\tif (this.inDrag === false && this.alwaysShowTooltip !== true) {\n\t\t\t\t\tthis._removeClass(this.tooltip, 'in');\n\t\t\t\t\tthis._removeClass(this.tooltip_min, 'in');\n\t\t\t\t\tthis._removeClass(this.tooltip_max, 'in');\n\t\t\t\t}\n\t\t\t\tthis.over = false;\n\t\t\t},\n\t\t\t_layout: function() {\n\t\t\t\tvar positionPercentages;\n\n\t\t\t\tif (this.options.reversed) {\n\t\t\t\t\tpositionPercentages = [100 - this.percentage[0], this.percentage[1]];\n\t\t\t\t} else {\n\t\t\t\t\tpositionPercentages = [this.percentage[0], this.percentage[1]];\n\t\t\t\t}\n\n\t\t\t\tthis.handle1.style[this.stylePos] = positionPercentages[0] + '%';\n\t\t\t\tthis.handle2.style[this.stylePos] = positionPercentages[1] + '%';\n\n\t\t\t\tif (this.options.orientation === 'vertical') {\n\t\t\t\t\tthis.trackSelection.style.top = Math.min(positionPercentages[0], positionPercentages[1]) + '%';\n\t\t\t\t\tthis.trackSelection.style.height = Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';\n\t\t\t\t} else {\n\t\t\t\t\tthis.trackSelection.style.left = Math.min(positionPercentages[0], positionPercentages[1]) + '%';\n\t\t\t\t\tthis.trackSelection.style.width = Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';\n\n\t\t\t\t\tvar offset_min = this.tooltip_min.getBoundingClientRect();\n\t\t\t\t\tvar offset_max = this.tooltip_max.getBoundingClientRect();\n\n\t\t\t\t\tif (offset_min.right > offset_max.left) {\n\t\t\t\t\t\tthis._removeClass(this.tooltip_max, 'top');\n\t\t\t\t\t\tthis._addClass(this.tooltip_max, 'bottom');\n\t\t\t\t\t\tthis.tooltip_max.style.top = 18 + 'px';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._removeClass(this.tooltip_max, 'bottom');\n\t\t\t\t\t\tthis._addClass(this.tooltip_max, 'top');\n\t\t\t\t\t\tthis.tooltip_max.style.top = this.tooltip_min.style.top;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar formattedTooltipVal;\n\n\t\t\t\tif (this.options.range) {\n\t\t\t\t\tformattedTooltipVal = this.options.formatter(this.options.value);\n\t\t\t\t\tthis._setText(this.tooltipInner, formattedTooltipVal);\n\t\t\t\t\tthis.tooltip.style[this.stylePos] = (positionPercentages[1] + positionPercentages[0]) / 2 + '%';\n\n\t\t\t\t\tif (this.options.orientation === 'vertical') {\n\t\t\t\t\t\tthis._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px');\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.options.orientation === 'vertical') {\n\t\t\t\t\t\tthis._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px');\n\t\t\t\t\t}\n\n\t\t\t\t\tvar innerTooltipMinText = this.options.formatter(this.options.value[0]);\n\t\t\t\t\tthis._setText(this.tooltipInner_min, innerTooltipMinText);\n\n\t\t\t\t\tvar innerTooltipMaxText = this.options.formatter(this.options.value[1]);\n\t\t\t\t\tthis._setText(this.tooltipInner_max, innerTooltipMaxText);\n\n\t\t\t\t\tthis.tooltip_min.style[this.stylePos] = positionPercentages[0] + '%';\n\n\t\t\t\t\tif (this.options.orientation === 'vertical') {\n\t\t\t\t\t\tthis._css(this.tooltip_min, 'margin-top', -this.tooltip_min.offsetHeight / 2 + 'px');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._css(this.tooltip_min, 'margin-left', -this.tooltip_min.offsetWidth / 2 + 'px');\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.tooltip_max.style[this.stylePos] = positionPercentages[1] + '%';\n\n\t\t\t\t\tif (this.options.orientation === 'vertical') {\n\t\t\t\t\t\tthis._css(this.tooltip_max, 'margin-top', -this.tooltip_max.offsetHeight / 2 + 'px');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._css(this.tooltip_max, 'margin-left', -this.tooltip_max.offsetWidth / 2 + 'px');\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tformattedTooltipVal = this.options.formatter(this.options.value[0]);\n\t\t\t\t\tthis._setText(this.tooltipInner, formattedTooltipVal);\n\n\t\t\t\t\tthis.tooltip.style[this.stylePos] = positionPercentages[0] + '%';\n\t\t\t\t\tif (this.options.orientation === 'vertical') {\n\t\t\t\t\t\tthis._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t_removeProperty: function(element, prop) {\n\t\t\t\tif (element.style.removeProperty) {\n\t\t\t\t\telement.style.removeProperty(prop);\n\t\t\t\t} else {\n\t\t\t\t\telement.style.removeAttribute(prop);\n\t\t\t\t}\n\t\t\t},\n\t\t\t_mousedown: function(ev) {\n\t\t\t\tif (!this.options.enabled) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tthis._triggerFocusOnHandle();\n\n\t\t\t\tthis.offset = this._offset(this.sliderElem);\n\t\t\t\tthis.size = this.sliderElem[this.sizePos];\n\n\t\t\t\tvar percentage = this._getPercentage(ev);\n\n\t\t\t\tif (this.options.range) {\n\t\t\t\t\tvar diff1 = Math.abs(this.percentage[0] - percentage);\n\t\t\t\t\tvar diff2 = Math.abs(this.percentage[1] - percentage);\n\t\t\t\t\tthis.dragged = (diff1 < diff2) ? 0 : 1;\n\t\t\t\t} else {\n\t\t\t\t\tthis.dragged = 0;\n\t\t\t\t}\n\n\t\t\t\tthis.percentage[this.dragged] = this.options.reversed ? 100 - percentage: percentage;\n\t\t\t\tthis._layout();\n\n\t\t\t\tif (this.touchCapable) {\n\t\t\t\t\tdocument.removeEventListener(\"touchmove\", this.mousemove, false);\n\t\t\t\t\tdocument.removeEventListener(\"touchend\", this.mouseup, false);\n\t\t\t\t}\n\n\t\t\t\tif (this.mousemove) {\n\t\t\t\t\tdocument.removeEventListener(\"mousemove\", this.mousemove, false);\n\t\t\t\t}\n\t\t\t\tif (this.mouseup) {\n\t\t\t\t\tdocument.removeEventListener(\"mouseup\", this.mouseup, false);\n\t\t\t\t}\n\n\t\t\t\tthis.mousemove = this._mousemove.bind(this);\n\t\t\t\tthis.mouseup = this._mouseup.bind(this);\n\n\t\t\t\tif (this.touchCapable) {\n\t\t\t\t\t// Touch: Bind touch events:\n\t\t\t\t\tdocument.addEventListener(\"touchmove\", this.mousemove, false);\n\t\t\t\t\tdocument.addEventListener(\"touchend\", this.mouseup, false);\n\t\t\t\t}\n\t\t\t\t// Bind mouse events:\n\t\t\t\tdocument.addEventListener(\"mousemove\", this.mousemove, false);\n\t\t\t\tdocument.addEventListener(\"mouseup\", this.mouseup, false);\n\n\t\t\t\tthis.inDrag = true;\n\t\t\t\tvar newValue = this._calculateValue();\n\n\t\t\t\tthis._trigger('slideStart', newValue);\n\n\t\t\t\tthis._setDataVal(newValue);\n\t\t\t\tthis.setValue(newValue);\n\n\t\t\t\tthis._pauseEvent(ev);\n\n\t\t\t\treturn true;\n\t\t\t},\n\t\t\t_triggerFocusOnHandle: function(handleIdx) {\n\t\t\t\tif (handleIdx === 0) {\n\t\t\t\t\tthis.handle1.focus();\n\t\t\t\t}\n\t\t\t\tif (handleIdx === 1) {\n\t\t\t\t\tthis.handle2.focus();\n\t\t\t\t}\n\t\t\t},\n\t\t\t_keydown: function(handleIdx, ev) {\n\t\t\t\tif (!this.options.enabled) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tvar dir;\n\t\t\t\tswitch (ev.keyCode) {\n\t\t\t\tcase 37:\n\t\t\t\t\t// left\n\t\t\t\tcase 40:\n\t\t\t\t\t// down\n\t\t\t\t\tdir = -1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 39:\n\t\t\t\t\t// right\n\t\t\t\tcase 38:\n\t\t\t\t\t// up\n\t\t\t\t\tdir = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (!dir) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// use natural arrow keys instead of from min to max\n\t\t\t\tif (this.options.natural_arrow_keys) {\n\t\t\t\t\tvar ifVerticalAndNotReversed = (this.options.orientation === 'vertical' && !this.options.reversed);\n\t\t\t\t\tvar ifHorizontalAndReversed = (this.options.orientation === 'horizontal' && this.options.reversed);\n\n\t\t\t\t\tif (ifVerticalAndNotReversed || ifHorizontalAndReversed) {\n\t\t\t\t\t\tdir = dir * -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar oneStepValuePercentageChange = dir * this.percentage[2];\n\t\t\t\tvar percentage = this.percentage[handleIdx] + oneStepValuePercentageChange;\n\n\t\t\t\tif (percentage > 100) {\n\t\t\t\t\tpercentage = 100;\n\t\t\t\t} else if (percentage < 0) {\n\t\t\t\t\tpercentage = 0;\n\t\t\t\t}\n\n\t\t\t\tthis.dragged = handleIdx;\n\t\t\t\tthis._adjustPercentageForRangeSliders(percentage);\n\t\t\t\tthis.percentage[this.dragged] = percentage;\n\t\t\t\tthis._layout();\n\n\t\t\t\tvar val = this._calculateValue();\n\n\t\t\t\tthis._trigger('slideStart', val);\n\t\t\t\tthis._setDataVal(val);\n\t\t\t\tthis.setValue(val, true);\n\n\t\t\t\tthis._trigger('slideStop', val);\n\t\t\t\tthis._setDataVal(val);\n\n\t\t\t\tthis._pauseEvent(ev);\n\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\t_pauseEvent: function(ev) {\n\t\t\t\tif (ev.stopPropagation) {\n\t\t\t\t\tev.stopPropagation();\n\t\t\t\t}\n\t\t\t\tif (ev.preventDefault) {\n\t\t\t\t\tev.preventDefault();\n\t\t\t\t}\n\t\t\t\tev.cancelBubble = true;\n\t\t\t\tev.returnValue = false;\n\t\t\t},\n\t\t\t_mousemove: function(ev) {\n\t\t\t\tif (!this.options.enabled) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tvar percentage = this._getPercentage(ev);\n\t\t\t\tthis._adjustPercentageForRangeSliders(percentage);\n\t\t\t\tthis.percentage[this.dragged] = this.options.reversed ? 100 - percentage: percentage;\n\t\t\t\tthis._layout();\n\n\t\t\t\tvar val = this._calculateValue();\n\t\t\t\tthis.setValue(val, true);\n\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\t_adjustPercentageForRangeSliders: function(percentage) {\n\t\t\t\tif (this.options.range) {\n\t\t\t\t\tif (this.dragged === 0 && this.percentage[1] < percentage) {\n\t\t\t\t\t\tthis.percentage[0] = this.percentage[1];\n\t\t\t\t\t\tthis.dragged = 1;\n\t\t\t\t\t} else if (this.dragged === 1 && this.percentage[0] > percentage) {\n\t\t\t\t\t\tthis.percentage[1] = this.percentage[0];\n\t\t\t\t\t\tthis.dragged = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t_mouseup: function() {\n\t\t\t\tif (!this.options.enabled) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (this.touchCapable) {\n\t\t\t\t\t// Touch: Unbind touch event handlers:\n\t\t\t\t\tdocument.removeEventListener(\"touchmove\", this.mousemove, false);\n\t\t\t\t\tdocument.removeEventListener(\"touchend\", this.mouseup, false);\n\t\t\t\t}\n\t\t\t\t// Unbind mouse event handlers:\n\t\t\t\tdocument.removeEventListener(\"mousemove\", this.mousemove, false);\n\t\t\t\tdocument.removeEventListener(\"mouseup\", this.mouseup, false);\n\n\t\t\t\tthis.inDrag = false;\n\t\t\t\tif (this.over === false) {\n\t\t\t\t\tthis._hideTooltip();\n\t\t\t\t}\n\t\t\t\tvar val = this._calculateValue();\n\n\t\t\t\tthis._layout();\n\t\t\t\tthis._trigger('slideStop', val);\n\t\t\t\tthis._setDataVal(val);\n\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\t_calculateValue: function() {\n\t\t\t\tvar val;\n\t\t\t\tif (this.options.range) {\n\t\t\t\t\tval = [this.options.min, this.options.max];\n\t\t\t\t\tif (this.percentage[0] !== 0) {\n\t\t\t\t\t\tval[0] = (Math.max(this.options.min, this.options.min + Math.round((this.diff * this.percentage[0] / 100) / this.options.step) * this.options.step));\n\t\t\t\t\t\tval[0] = this._applyPrecision(val[0]);\n\t\t\t\t\t}\n\t\t\t\t\tif (this.percentage[1] !== 100) {\n\t\t\t\t\t\tval[1] = (Math.min(this.options.max, this.options.min + Math.round((this.diff * this.percentage[1] / 100) / this.options.step) * this.options.step));\n\t\t\t\t\t\tval[1] = this._applyPrecision(val[1]);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tval = (this.options.min + Math.round((this.diff * this.percentage[0] / 100) / this.options.step) * this.options.step);\n\t\t\t\t\tif (val < this.options.min) {\n\t\t\t\t\t\tval = this.options.min;\n\t\t\t\t\t} else if (val > this.options.max) {\n\t\t\t\t\t\tval = this.options.max;\n\t\t\t\t\t}\n\t\t\t\t\tval = parseFloat(val);\n\t\t\t\t\tval = this._applyPrecision(val);\n\t\t\t\t}\n\t\t\t\treturn val;\n\t\t\t},\n\t\t\t_applyPrecision: function(val) {\n\t\t\t\tvar precision = this.options.precision || this._getNumDigitsAfterDecimalPlace(this.options.step);\n\t\t\t\treturn this._applyToFixedAndParseFloat(val, precision);\n\t\t\t},\n\t\t\t_getNumDigitsAfterDecimalPlace: function(num) {\n\t\t\t\tvar match = ('' + num).match(/(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/);\n\t\t\t\tif (!match) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\treturn Math.max(0, (match[1] ? match[1].length: 0) - (match[2] ? +match[2] : 0));\n\t\t\t},\n\t\t\t_applyToFixedAndParseFloat: function(num, toFixedInput) {\n\t\t\t\tvar truncatedNum = num.toFixed(toFixedInput);\n\t\t\t\treturn parseFloat(truncatedNum);\n\t\t\t},\n\t\t\t/*\n\t\t\t\tCredits to Mike Samuel for the following method!\n\t\t\t\tSource: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number\n\t\t\t*/\n\t\t\t_getPercentage: function(ev) {\n\t\t\t\tif (this.touchCapable && (ev.type === 'touchstart' || ev.type === 'touchmove')) {\n\t\t\t\t\tev = ev.touches[0];\n\t\t\t\t}\n\t\t\t\tvar percentage = (ev[this.mousePos] - this.offset[this.stylePos]) * 100 / this.size;\n\t\t\t\tpercentage = Math.round(percentage / this.percentage[2]) * this.percentage[2];\n\t\t\t\treturn Math.max(0, Math.min(100, percentage));\n\t\t\t},\n\t\t\t_validateInputValue: function(val) {\n\t\t\t\tif (typeof val === 'number') {\n\t\t\t\t\treturn val;\n\t\t\t\t} else if (val instanceof Array) {\n\t\t\t\t\tthis._validateArray(val);\n\t\t\t\t\treturn val;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(ErrorMsgs.formatInvalidInputErrorMsg(val));\n\t\t\t\t}\n\t\t\t},\n\t\t\t_validateArray: function(val) {\n\t\t\t\tfor (var i = 0; i < val.length; i++) {\n\t\t\t\t\tvar input = val[i];\n\t\t\t\t\tif (typeof input !== 'number') {\n\t\t\t\t\t\tthrow new Error(ErrorMsgs.formatInvalidInputErrorMsg(input));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t_setDataVal: function(val) {\n\t\t\t\tvar value = \"value: '\" + val + \"'\";\n\t\t\t\tthis.element.setAttribute('data', value);\n\t\t\t\tthis.element.setAttribute('value', val);\n\t\t\t},\n\t\t\t_trigger: function(evt, val) {\n\t\t\t\tval = (val || val === 0) ? val: undefined;\n\n\t\t\t\tvar callbackFnArray = this.eventToCallbackMap[evt];\n\t\t\t\tif (callbackFnArray && callbackFnArray.length) {\n\t\t\t\t\tfor (var i = 0; i < callbackFnArray.length; i++) {\n\t\t\t\t\t\tvar callbackFn = callbackFnArray[i];\n\t\t\t\t\t\tcallbackFn(val);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* If JQuery exists, trigger JQuery events */\n\t\t\t\tif ($) {\n\t\t\t\t\tthis._triggerJQueryEvent(evt, val);\n\t\t\t\t}\n\t\t\t},\n\t\t\t_triggerJQueryEvent: function(evt, val) {\n\t\t\t\tvar eventData = {\n\t\t\t\t\ttype: evt,\n\t\t\t\t\tvalue: val\n\t\t\t\t};\n\t\t\t\tthis.$element.trigger(eventData);\n\t\t\t\tthis.$sliderElem.trigger(eventData);\n\t\t\t},\n\t\t\t_unbindJQueryEventHandlers: function() {\n\t\t\t\tthis.$element.off();\n\t\t\t\tthis.$sliderElem.off();\n\t\t\t},\n\t\t\t_setText: function(element, text) {\n\t\t\t\tif (typeof element.innerText !== \"undefined\") {\n\t\t\t\t\telement.innerText = text;\n\t\t\t\t} else if (typeof element.textContent !== \"undefined\") {\n\t\t\t\t\telement.textContent = text;\n\t\t\t\t}\n\t\t\t},\n\t\t\t_removeClass: function(element, classString) {\n\t\t\t\tvar classes = classString.split(\" \");\n\t\t\t\tvar newClasses = element.className;\n\n\t\t\t\tfor (var i = 0; i < classes.length; i++) {\n\t\t\t\t\tvar classTag = classes[i];\n\t\t\t\t\tvar regex = new RegExp(\"(?:\\\\s|^)\" + classTag + \"(?:\\\\s|$)\");\n\t\t\t\t\tnewClasses = newClasses.replace(regex, \" \");\n\t\t\t\t}\n\n\t\t\t\telement.className = newClasses.trim();\n\t\t\t},\n\t\t\t_addClass: function(element, classString) {\n\t\t\t\tvar classes = classString.split(\" \");\n\t\t\t\tvar newClasses = element.className;\n\n\t\t\t\tfor (var i = 0; i < classes.length; i++) {\n\t\t\t\t\tvar classTag = classes[i];\n\t\t\t\t\tvar regex = new RegExp(\"(?:\\\\s|^)\" + classTag + \"(?:\\\\s|$)\");\n\t\t\t\t\tvar ifClassExists = regex.test(newClasses);\n\n\t\t\t\t\tif (!ifClassExists) {\n\t\t\t\t\t\tnewClasses += \" \" + classTag;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telement.className = newClasses.trim();\n\t\t\t},\n\t\t\t_offset: function(obj) {\n\t\t\t\tvar ol = 0;\n\t\t\t\tvar ot = 0;\n\t\t\t\tif (obj.offsetParent) {\n\t\t\t\t\tdo {\n\t\t\t\t\t\tol += obj.offsetLeft;\n\t\t\t\t\t\tot += obj.offsetTop;\n\t\t\t\t\t} while ( obj = obj . offsetParent );\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tleft: ol,\n\t\t\t\t\ttop: ot\n\t\t\t\t};\n\t\t\t},\n\t\t\t_css: function(elementRef, styleName, value) {\n\t\t\t\tif ($) {\n\t\t\t\t\t$.style(elementRef, styleName, value);\n\t\t\t\t} else {\n\t\t\t\t\tvar style = styleName.replace(/^-ms-/, \"ms-\").replace(/-([\\da-z])/gi,\n\t\t\t\t\tfunction(all, letter) {\n\t\t\t\t\t\treturn letter.toUpperCase();\n\t\t\t\t\t});\n\t\t\t\t\telementRef.style[style] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t/*********************************\n\t\t\tAttach to global namespace\n\t\t*********************************/\n\t\tif ($) {\n\t\t\tvar namespace = $.fn.slider ? 'bootstrapSlider': 'slider';\n\t\t\t$.bridget(namespace, Slider);\n\t\t}\n\t})($);\n\treturn Slider;\n}));\n\n/* =========================================================\n* Bootstrap.datetimepicker.js\n* =========================================================\n* Copyright 2012 Stefan Petre\n*\n* Improvements by Andrew Rowls\n* Improvements by Sébastien Malot\n* Improvements by Yun Lai\n* Improvements by Kenneth Henderick\n* Improvements by CuGBabyBeaR\n* Improvements by Christian Vaas <auspex@auspex.eu>\n*\n* Project URL : http://www.malot.fr/bootstrap-datetimepicker\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! (function(factory) {\n\tif (typeof define === 'function' && define.amd) define(['jquery'], factory);\n\telse if (typeof exports === 'object') factory(require('jquery'));\n\telse factory(jQuery);\n} (function($, undefined) {\n\t// Add ECMA262-5 Array methods if not supported natively (IE8)\n\tif (! ('indexOf' in Array.prototype)) {\n\t\tArray.prototype.indexOf = function(find, i) {\n\t\t\tif (i === undefined) i = 0;\n\t\t\tif (i < 0) i += this.length;\n\t\t\tif (i < 0) i = 0;\n\t\t\tfor (var n = this.length; i < n; i++) {\n\t\t\t\tif (i in this && this[i] === find) {\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\t}\n\n\tfunction elementOrParentIsFixed(element) {\n\t\tvar $element = $(element);\n\t\tvar $checkElements = $element.add($element.parents());\n\t\tvar isFixed = false;\n\t\t$checkElements.each(function() {\n\t\t\tif ($(this).css('position') === 'fixed') {\n\t\t\t\tisFixed = true;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t\treturn isFixed;\n\t}\n\n\tfunction UTCDate() {\n\t\treturn new Date(Date.UTC.apply(Date, arguments));\n\t}\n\n\tfunction UTCToday() {\n\t\tvar today = new Date();\n\t\treturn UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate(), today.getUTCHours(), today.getUTCMinutes(), today.getUTCSeconds(), 0);\n\t}\n\n\t// Picker object\n\tvar Datetimepicker = function(element, options) {\n\t\tvar that = this;\n\t\tthis.element = $(element);\n\n\t\t// add container for single page application\n\t\t// when page switch the datetimepicker div will be removed also.\n\t\tthis.container = options.container || 'body';\n\n\t\tthis.language = options.language || this.element.data('date-language') || 'en';\n\t\tthis.language = this.language in dates ? this.language: this.language.split('-')[0]; // fr-CA fallback to fr\n\t\tthis.language = this.language in dates ? this.language: 'en';\n\t\tthis.isRTL = dates[this.language].rtl || false;\n\t\tthis.formatType = options.formatType || this.element.data('format-type') || 'standard';\n\t\tthis.format = DPGlobal.parseFormat(options.format || this.element.data('date-format') || dates[this.language].format || DPGlobal.getDefaultFormat(this.formatType, 'input'), this.formatType);\n\t\tthis.isInline = false;\n\t\tthis.isVisible = false;\n\t\tthis.isInput = this.element.is('input');\n\t\tthis.fontAwesome = options.fontAwesome || this.element.data('font-awesome') || false;\n\n\t\tthis.bootcssVer = options.bootcssVer || (this.isInput ? (this.element.is('.form-control') ? 3 : 2) : (this.bootcssVer = this.element.is('.input-group') ? 3 : 2));\n\n\t\tthis.component = this.element.is('.date') ? (this.bootcssVer == 3 ? this.element.find('.input-group-addon .glyphicon-th, .input-group-addon .glyphicon-time, .input-group-addon .glyphicon-remove, .input-group-addon .glyphicon-calendar, .input-group-addon .fa-calendar, .input-group-addon .fa-clock-o').parent() : this.element.find('.add-on .icon-th, .add-on .icon-time, .add-on .icon-calendar, .add-on .fa-calendar, .add-on .fa-clock-o').parent()) : false;\n\t\tthis.componentReset = this.element.is('.date') ? (this.bootcssVer == 3 ? this.element.find('.input-group-addon .glyphicon-remove, .input-group-addon .fa-times').parent() : this.element.find('.add-on .icon-remove, .add-on .fa-times').parent()) : false;\n\t\tthis.hasInput = this.component && this.element.find('input').length;\n\t\tif (this.component && this.component.length === 0) {\n\t\t\tthis.component = false;\n\t\t}\n\t\tthis.linkField = options.linkField || this.element.data('link-field') || false;\n\t\tthis.linkFormat = DPGlobal.parseFormat(options.linkFormat || this.element.data('link-format') || DPGlobal.getDefaultFormat(this.formatType, 'link'), this.formatType);\n\t\tthis.minuteStep = options.minuteStep || this.element.data('minute-step') || 5;\n\t\tthis.pickerPosition = options.pickerPosition || this.element.data('picker-position') || 'bottom-right';\n\t\tthis.showMeridian = options.showMeridian || this.element.data('show-meridian') || false;\n\t\tthis.initialDate = options.initialDate || new Date();\n\t\tthis.zIndex = options.zIndex || this.element.data('z-index') || undefined;\n\t\tthis.title = typeof options.title === 'undefined' ? false: options.title;\n\t\tthis.defaultTimeZone = (new Date).toString().split('(')[1].slice(0, -1);\n\t\tthis.timezone = options.timezone || this.defaultTimeZone;\n\n\t\tthis.icons = {\n\t\t\tleftArrow: this.fontAwesome ? 'fa-arrow-left': (this.bootcssVer === 3 ? 'glyphicon-arrow-left': 'icon-arrow-left'),\n\t\t\trightArrow: this.fontAwesome ? 'fa-arrow-right': (this.bootcssVer === 3 ? 'glyphicon-arrow-right': 'icon-arrow-right')\n\t\t}\n\t\tthis.icontype = this.fontAwesome ? 'fa': 'glyphicon';\n\t\tthis._attachEvents();\n\t\tthis.clickedOutside = function(e) {\n\t\t\t// Clicked outside the datetimepicker, hide it\n\t\t\tif ($(e.target).closest('.datetimepicker').length === 0) {\n\t\t\t\tthat.hide();\n\t\t\t}\n\t\t}\n\n\t\tthis.formatViewType = 'datetime';\n\t\tif ('formatViewType' in options) {\n\t\t\tthis.formatViewType = options.formatViewType;\n\t\t} else if ('formatViewType' in this.element.data()) {\n\t\t\tthis.formatViewType = this.element.data('formatViewType');\n\t\t}\n\n\t\tthis.minView = 0;\n\t\tif ('minView' in options) {\n\t\t\tthis.minView = options.minView;\n\t\t} else if ('minView' in this.element.data()) {\n\t\t\tthis.minView = this.element.data('min-view');\n\t\t}\n\t\tthis.minView = DPGlobal.convertViewMode(this.minView);\n\n\t\tthis.maxView = DPGlobal.modes.length - 1;\n\t\tif ('maxView' in options) {\n\t\t\tthis.maxView = options.maxView;\n\t\t} else if ('maxView' in this.element.data()) {\n\t\t\tthis.maxView = this.element.data('max-view');\n\t\t}\n\t\tthis.maxView = DPGlobal.convertViewMode(this.maxView);\n\n\t\tthis.wheelViewModeNavigation = false;\n\t\tif ('wheelViewModeNavigation' in options) {\n\t\t\tthis.wheelViewModeNavigation = options.wheelViewModeNavigation;\n\t\t} else if ('wheelViewModeNavigation' in this.element.data()) {\n\t\t\tthis.wheelViewModeNavigation = this.element.data('view-mode-wheel-navigation');\n\t\t}\n\n\t\tthis.wheelViewModeNavigationInverseDirection = false;\n\n\t\tif ('wheelViewModeNavigationInverseDirection' in options) {\n\t\t\tthis.wheelViewModeNavigationInverseDirection = options.wheelViewModeNavigationInverseDirection;\n\t\t} else if ('wheelViewModeNavigationInverseDirection' in this.element.data()) {\n\t\t\tthis.wheelViewModeNavigationInverseDirection = this.element.data('view-mode-wheel-navigation-inverse-dir');\n\t\t}\n\n\t\tthis.wheelViewModeNavigationDelay = 100;\n\t\tif ('wheelViewModeNavigationDelay' in options) {\n\t\t\tthis.wheelViewModeNavigationDelay = options.wheelViewModeNavigationDelay;\n\t\t} else if ('wheelViewModeNavigationDelay' in this.element.data()) {\n\t\t\tthis.wheelViewModeNavigationDelay = this.element.data('view-mode-wheel-navigation-delay');\n\t\t}\n\n\t\tthis.startViewMode = 2;\n\t\tif ('startView' in options) {\n\t\t\tthis.startViewMode = options.startView;\n\t\t} else if ('startView' in this.element.data()) {\n\t\t\tthis.startViewMode = this.element.data('start-view');\n\t\t}\n\t\tthis.startViewMode = DPGlobal.convertViewMode(this.startViewMode);\n\t\tthis.viewMode = this.startViewMode;\n\n\t\tthis.viewSelect = this.minView;\n\t\tif ('viewSelect' in options) {\n\t\t\tthis.viewSelect = options.viewSelect;\n\t\t} else if ('viewSelect' in this.element.data()) {\n\t\t\tthis.viewSelect = this.element.data('view-select');\n\t\t}\n\t\tthis.viewSelect = DPGlobal.convertViewMode(this.viewSelect);\n\n\t\tthis.forceParse = true;\n\t\tif ('forceParse' in options) {\n\t\t\tthis.forceParse = options.forceParse;\n\t\t} else if ('dateForceParse' in this.element.data()) {\n\t\t\tthis.forceParse = this.element.data('date-force-parse');\n\t\t}\n\t\tvar template = this.bootcssVer === 3 ? DPGlobal.templateV3: DPGlobal.template;\n\t\twhile (template.indexOf('{iconType}') !== -1) {\n\t\t\ttemplate = template.replace('{iconType}', this.icontype);\n\t\t}\n\t\twhile (template.indexOf('{leftArrow}') !== -1) {\n\t\t\ttemplate = template.replace('{leftArrow}', this.icons.leftArrow);\n\t\t}\n\t\twhile (template.indexOf('{rightArrow}') !== -1) {\n\t\t\ttemplate = template.replace('{rightArrow}', this.icons.rightArrow);\n\t\t}\n\t\tthis.picker = $(template).appendTo(this.isInline ? this.element: this.container) // 'body')\n\t\t.on({\n\t\t\tclick: $.proxy(this.click, this),\n\t\t\tmousedown: $.proxy(this.mousedown, this)\n\t\t});\n\n\t\tif (this.wheelViewModeNavigation) {\n\t\t\tif ($.fn.mousewheel) {\n\t\t\t\tthis.picker.on({\n\t\t\t\t\tmousewheel: $.proxy(this.mousewheel, this)\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconsole.log('Mouse Wheel event is not supported. Please include the jQuery Mouse Wheel plugin before enabling this option');\n\t\t\t}\n\t\t}\n\n\t\tif (this.isInline) {\n\t\t\tthis.picker.addClass('datetimepicker-inline');\n\t\t} else {\n\t\t\tthis.picker.addClass('datetimepicker-dropdown-' + this.pickerPosition + ' dropdown-menu');\n\t\t}\n\t\tif (this.isRTL) {\n\t\t\tthis.picker.addClass('datetimepicker-rtl');\n\t\t\tvar selector = this.bootcssVer === 3 ? '.prev span, .next span': '.prev i, .next i';\n\t\t\tthis.picker.find(selector).toggleClass(this.icons.leftArrow + ' ' + this.icons.rightArrow);\n\t\t}\n\n\t\t$(document).on('mousedown', this.clickedOutside);\n\t\tthis.autoclose = false;\n\t\tif ('autoclose' in options) {\n\t\t\tthis.autoclose = options.autoclose;\n\t\t} else if ('dateAutoclose' in this.element.data()) {\n\t\t\tthis.autoclose = this.element.data('date-autoclose');\n\t\t}\n\n\t\tthis.keyboardNavigation = true;\n\t\tif ('keyboardNavigation' in options) {\n\t\t\tthis.keyboardNavigation = options.keyboardNavigation;\n\t\t} else if ('dateKeyboardNavigation' in this.element.data()) {\n\t\t\tthis.keyboardNavigation = this.element.data('date-keyboard-navigation');\n\t\t}\n\n\t\tthis.todayBtn = (options.todayBtn || this.element.data('date-today-btn') || false);\n\t\tthis.clearBtn = (options.clearBtn || this.element.data('date-clear-btn') || false);\n\t\tthis.todayHighlight = (options.todayHighlight || this.element.data('date-today-highlight') || false);\n\n\t\tthis.weekStart = ((options.weekStart || this.element.data('date-weekstart') || dates[this.language].weekStart || 0) % 7);\n\t\tthis.weekEnd = ((this.weekStart + 6) % 7);\n\t\tthis.startDate = -Infinity;\n\t\tthis.endDate = Infinity;\n\t\tthis.datesDisabled = [];\n\t\tthis.daysOfWeekDisabled = [];\n\t\tthis.setStartDate(options.startDate || this.element.data('date-startdate'));\n\t\tthis.setEndDate(options.endDate || this.element.data('date-enddate'));\n\t\tthis.setDatesDisabled(options.datesDisabled || this.element.data('date-dates-disabled'));\n\t\tthis.setDaysOfWeekDisabled(options.daysOfWeekDisabled || this.element.data('date-days-of-week-disabled'));\n\t\tthis.setMinutesDisabled(options.minutesDisabled || this.element.data('date-minute-disabled'));\n\t\tthis.setHoursDisabled(options.hoursDisabled || this.element.data('date-hour-disabled'));\n\t\tthis.fillDow();\n\t\tthis.fillMonths();\n\t\tthis.update();\n\t\tthis.showMode();\n\n\t\tif (this.isInline) {\n\t\t\tthis.show();\n\t\t}\n\t};\n\n\tDatetimepicker.prototype = {\n\t\tconstructor: Datetimepicker,\n\t\t_events: [],\n\t\t_attachEvents: function() {\n\t\t\tthis._detachEvents();\n\t\t\tif (this.isInput) { // single input\n\t\t\t\tthis._events = [[this.element, {\n\t\t\t\t\tfocus: $.proxy(this.show, this),\n\t\t\t\t\tkeyup: $.proxy(this.update, this),\n\t\t\t\t\tkeydown: $.proxy(this.keydown, this)\n\t\t\t\t}]];\n\t\t\t} else if (this.component && this.hasInput) { // component: input + button\n\t\t\t\tthis._events = [\n\t\t\t\t// For components that are not readonly, allow keyboard nav\n\t\t\t\t[this.element.find('input'), {\n\t\t\t\t\tfocus: $.proxy(this.show, this),\n\t\t\t\t\tkeyup: $.proxy(this.update, this),\n\t\t\t\t\tkeydown: $.proxy(this.keydown, this)\n\t\t\t\t}], [this.component, {\n\t\t\t\t\tclick: $.proxy(this.show, this)\n\t\t\t\t}]];\n\t\t\t\tif (this.componentReset) {\n\t\t\t\t\tthis._events.push([this.componentReset, {\n\t\t\t\t\t\tclick: $.proxy(this.reset, this)\n\t\t\t\t\t}]);\n\t\t\t\t}\n\t\t\t} else if (this.element.is('div')) { // inline datetimepicker\n\t\t\t\tthis.isInline = true;\n\t\t\t} else {\n\t\t\t\tthis._events = [[this.element, {\n\t\t\t\t\tclick: $.proxy(this.show, this)\n\t\t\t\t}]];\n\t\t\t}\n\t\t\tfor (var i = 0,\n\t\t\tel, ev; i < this._events.length; i++) {\n\t\t\t\tel = this._events[i][0];\n\t\t\t\tev = this._events[i][1];\n\t\t\t\tel.on(ev);\n\t\t\t}\n\t\t},\n\n\t\t_detachEvents: function() {\n\t\t\tfor (var i = 0,\n\t\t\tel, ev; i < this._events.length; i++) {\n\t\t\t\tel = this._events[i][0];\n\t\t\t\tev = this._events[i][1];\n\t\t\t\tel.off(ev);\n\t\t\t}\n\t\t\tthis._events = [];\n\t\t},\n\n\t\tshow: function(e) {\n\t\t\tthis.picker.show();\n\t\t\tthis.height = this.component ? this.component.outerHeight() : this.element.outerHeight();\n\t\t\tif (this.forceParse) {\n\t\t\t\tthis.update();\n\t\t\t}\n\t\t\tthis.place();\n\t\t\t$(window).on('resize', $.proxy(this.place, this));\n\t\t\tif (e) {\n\t\t\t\te.stopPropagation();\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t\tthis.isVisible = true;\n\t\t\tthis.element.trigger({\n\t\t\t\ttype: 'show',\n\t\t\t\tdate: this.date\n\t\t\t});\n\t\t},\n\n\t\thide: function(e) {\n\t\t\tif (!this.isVisible) return;\n\t\t\tif (this.isInline) return;\n\t\t\tthis.picker.hide();\n\t\t\t$(window).off('resize', this.place);\n\t\t\tthis.viewMode = this.startViewMode;\n\t\t\tthis.showMode();\n\t\t\tif (!this.isInput) {\n\t\t\t\t$(document).off('mousedown', this.hide);\n\t\t\t}\n\t\t\tif (this.forceParse && (this.isInput && this.element.val() || this.hasInput && this.element.find('input').val())) this.setValue();\n\t\t\tthis.isVisible = false;\n\t\t\tthis.element.trigger({\n\t\t\t\ttype: 'hide',\n\t\t\t\tdate: this.date\n\t\t\t});\n\t\t},\n\n\t\tremove: function() {\n\t\t\tthis._detachEvents();\n\t\t\t$(document).off('mousedown', this.clickedOutside);\n\t\t\tthis.picker.remove();\n\t\t\tdelete this.picker;\n\t\t\tdelete this.element.data().datetimepicker;\n\t\t},\n\n\t\tgetDate: function() {\n\t\t\tvar d = this.getUTCDate();\n\t\t\treturn new Date(d.getTime() + (d.getTimezoneOffset() * 60000));\n\t\t},\n\n\t\tgetUTCDate: function() {\n\t\t\treturn this.date;\n\t\t},\n\n\t\tgetInitialDate: function() {\n\t\t\treturn this.initialDate\n\t\t},\n\n\t\tsetInitialDate: function(initialDate) {\n\t\t\tthis.initialDate = initialDate;\n\t\t},\n\n\t\tsetDate: function(d) {\n\t\t\tthis.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset() * 60000)));\n\t\t},\n\n\t\tsetUTCDate: function(d) {\n\t\t\tif (d >= this.startDate && d <= this.endDate) {\n\t\t\t\tthis.date = d;\n\t\t\t\tthis.setValue();\n\t\t\t\tthis.viewDate = this.date;\n\t\t\t\tthis.fill();\n\t\t\t} else {\n\t\t\t\tthis.element.trigger({\n\t\t\t\t\ttype: 'outOfRange',\n\t\t\t\t\tdate: d,\n\t\t\t\t\tstartDate: this.startDate,\n\t\t\t\t\tendDate: this.endDate\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\n\t\tsetFormat: function(format) {\n\t\t\tthis.format = DPGlobal.parseFormat(format, this.formatType);\n\t\t\tvar element;\n\t\t\tif (this.isInput) {\n\t\t\t\telement = this.element;\n\t\t\t} else if (this.component) {\n\t\t\t\telement = this.element.find('input');\n\t\t\t}\n\t\t\tif (element && element.val()) {\n\t\t\t\tthis.setValue();\n\t\t\t}\n\t\t},\n\n\t\tsetValue: function() {\n\t\t\tvar formatted = this.getFormattedDate();\n\t\t\tif (!this.isInput) {\n\t\t\t\tif (this.component) {\n\t\t\t\t\tthis.element.find('input').val(formatted);\n\t\t\t\t}\n\t\t\t\tthis.element.data('date', formatted);\n\t\t\t} else {\n\t\t\t\tthis.element.val(formatted);\n\t\t\t}\n\t\t\tif (this.linkField) {\n\t\t\t\t$('#' + this.linkField).val(this.getFormattedDate(this.linkFormat));\n\t\t\t}\n\t\t},\n\n\t\tgetFormattedDate: function(format) {\n\t\t\tif (format == undefined) format = this.format;\n\t\t\treturn DPGlobal.formatDate(this.date, format, this.language, this.formatType, this.timezone);\n\t\t},\n\n\t\tsetStartDate: function(startDate) {\n\t\t\tthis.startDate = startDate || -Infinity;\n\t\t\tif (this.startDate !== -Infinity) {\n\t\t\t\tthis.startDate = DPGlobal.parseDate(this.startDate, this.format, this.language, this.formatType, this.timezone);\n\t\t\t}\n\t\t\tthis.update();\n\t\t\tthis.updateNavArrows();\n\t\t},\n\n\t\tsetEndDate: function(endDate) {\n\t\t\tthis.endDate = endDate || Infinity;\n\t\t\tif (this.endDate !== Infinity) {\n\t\t\t\tthis.endDate = DPGlobal.parseDate(this.endDate, this.format, this.language, this.formatType, this.timezone);\n\t\t\t}\n\t\t\tthis.update();\n\t\t\tthis.updateNavArrows();\n\t\t},\n\n\t\tsetDatesDisabled: function(datesDisabled) {\n\t\t\tthis.datesDisabled = datesDisabled || [];\n\t\t\tif (!$.isArray(this.datesDisabled)) {\n\t\t\t\tthis.datesDisabled = this.datesDisabled.split(/,\\s*/);\n\t\t\t}\n\t\t\tthis.datesDisabled = $.map(this.datesDisabled,\n\t\t\tfunction(d) {\n\t\t\t\treturn DPGlobal.parseDate(d, this.format, this.language, this.formatType, this.timezone).toDateString();\n\t\t\t});\n\t\t\tthis.update();\n\t\t\tthis.updateNavArrows();\n\t\t},\n\n\t\tsetTitle: function(selector, value) {\n\t\t\treturn this.picker.find(selector).find('th:eq(1)').text(this.title === false ? value: this.title);\n\t\t},\n\n\t\tsetDaysOfWeekDisabled: function(daysOfWeekDisabled) {\n\t\t\tthis.daysOfWeekDisabled = daysOfWeekDisabled || [];\n\t\t\tif (!$.isArray(this.daysOfWeekDisabled)) {\n\t\t\t\tthis.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\\s*/);\n\t\t\t}\n\t\t\tthis.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled,\n\t\t\tfunction(d) {\n\t\t\t\treturn parseInt(d, 10);\n\t\t\t});\n\t\t\tthis.update();\n\t\t\tthis.updateNavArrows();\n\t\t},\n\n\t\tsetMinutesDisabled: function(minutesDisabled) {\n\t\t\tthis.minutesDisabled = minutesDisabled || [];\n\t\t\tif (!$.isArray(this.minutesDisabled)) {\n\t\t\t\tthis.minutesDisabled = this.minutesDisabled.split(/,\\s*/);\n\t\t\t}\n\t\t\tthis.minutesDisabled = $.map(this.minutesDisabled,\n\t\t\tfunction(d) {\n\t\t\t\treturn parseInt(d, 10);\n\t\t\t});\n\t\t\tthis.update();\n\t\t\tthis.updateNavArrows();\n\t\t},\n\n\t\tsetHoursDisabled: function(hoursDisabled) {\n\t\t\tthis.hoursDisabled = hoursDisabled || [];\n\t\t\tif (!$.isArray(this.hoursDisabled)) {\n\t\t\t\tthis.hoursDisabled = this.hoursDisabled.split(/,\\s*/);\n\t\t\t}\n\t\t\tthis.hoursDisabled = $.map(this.hoursDisabled,\n\t\t\tfunction(d) {\n\t\t\t\treturn parseInt(d, 10);\n\t\t\t});\n\t\t\tthis.update();\n\t\t\tthis.updateNavArrows();\n\t\t},\n\n\t\tplace: function() {\n\t\t\tif (this.isInline) return;\n\t\t\tif (!this.zIndex) {\n\t\t\t\tvar index_highest = 0;\n\t\t\t\t$('div').each(function() {\n\t\t\t\t\tvar index_current = parseInt($(this).css('zIndex'), 10);\n\t\t\t\t\tif (index_current > index_highest) {\n\t\t\t\t\t\tindex_highest = index_current;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tthis.zIndex = index_highest + 10;\n\t\t\t}\n\n\t\t\tvar offset, top, left, containerOffset;\n\t\t\tif (this.container instanceof $) {\n\t\t\t\tcontainerOffset = this.container.offset();\n\t\t\t} else {\n\t\t\t\tcontainerOffset = $(this.container).offset();\n\t\t\t}\n\n\t\t\tif (this.component) {\n\t\t\t\toffset = this.component.offset();\n\t\t\t\tleft = offset.left;\n\t\t\t\tif (this.pickerPosition == 'bottom-left' || this.pickerPosition == 'top-left') {\n\t\t\t\t\tleft += this.component.outerWidth() - this.picker.outerWidth();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\toffset = this.element.offset();\n\t\t\t\tleft = offset.left;\n\t\t\t\tif (this.pickerPosition == 'bottom-left' || this.pickerPosition == 'top-left') {\n\t\t\t\t\tleft += this.element.outerWidth() - this.picker.outerWidth();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar bodyWidth = document.body.clientWidth || window.innerWidth;\n\t\t\tif (left + 220 > bodyWidth) {\n\t\t\t\tleft = bodyWidth - 220;\n\t\t\t}\n\n\t\t\tif (this.pickerPosition == 'top-left' || this.pickerPosition == 'top-right') {\n\t\t\t\ttop = offset.top - this.picker.outerHeight();\n\t\t\t} else {\n\t\t\t\ttop = offset.top + this.height;\n\t\t\t}\n\n\t\t\ttop = top - containerOffset.top;\n\t\t\tleft = left - containerOffset.left;\n\n\t\t\tthis.picker.css({\n\t\t\t\ttop: top,\n\t\t\t\tleft: left,\n\t\t\t\tzIndex: this.zIndex\n\t\t\t});\n\t\t},\n\n\t\tupdate: function() {\n\t\t\tvar date, fromArgs = false;\n\t\t\tif (arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {\n\t\t\t\tdate = arguments[0];\n\t\t\t\tfromArgs = true;\n\t\t\t} else {\n\t\t\t\tdate = (this.isInput ? this.element.val() : this.element.find('input').val()) || this.element.data('date') || this.initialDate;\n\t\t\t\tif (typeof date == 'string' || date instanceof String) {\n\t\t\t\t\tdate = date.replace(/^\\s+|\\s+$/g, '');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!date) {\n\t\t\t\tdate = new Date();\n\t\t\t\tfromArgs = false;\n\t\t\t}\n\n\t\t\tthis.date = DPGlobal.parseDate(date, this.format, this.language, this.formatType, this.timezone);\n\n\t\t\tif (fromArgs) this.setValue();\n\n\t\t\tif (this.date < this.startDate) {\n\t\t\t\tthis.viewDate = new Date(this.startDate);\n\t\t\t} else if (this.date > this.endDate) {\n\t\t\t\tthis.viewDate = new Date(this.endDate);\n\t\t\t} else {\n\t\t\t\tthis.viewDate = new Date(this.date);\n\t\t\t}\n\t\t\tthis.fill();\n\t\t},\n\n\t\tfillDow: function() {\n\t\t\tvar dowCnt = this.weekStart,\n\t\t\thtml = '<tr>';\n\t\t\twhile (dowCnt < this.weekStart + 7) {\n\t\t\t\thtml += '<th class=\"dow\">' + dates[this.language].daysMin[(dowCnt++) % 7] + '</th>';\n\t\t\t}\n\t\t\thtml += '</tr>';\n\t\t\tthis.picker.find('.datetimepicker-days thead').append(html);\n\t\t},\n\n\t\tfillMonths: function() {\n\t\t\tvar html = '',\n\t\t\ti = 0;\n\t\t\twhile (i < 12) {\n\t\t\t\thtml += '<span class=\"month\">' + dates[this.language].monthsShort[i++] + '</span>';\n\t\t\t}\n\t\t\tthis.picker.find('.datetimepicker-months td').html(html);\n\t\t},\n\n\t\tfill: function() {\n\t\t\tif (this.date == null || this.viewDate == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar d = new Date(this.viewDate),\n\t\t\tyear = d.getUTCFullYear(),\n\t\t\tmonth = d.getUTCMonth(),\n\t\t\tdayMonth = d.getUTCDate(),\n\t\t\thours = d.getUTCHours(),\n\t\t\tminutes = d.getUTCMinutes(),\n\t\t\tstartYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,\n\t\t\tstartMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,\n\t\t\tendYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,\n\t\t\tendMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() + 1 : Infinity,\n\t\t\tcurrentDate = (new UTCDate(this.date.getUTCFullYear(), this.date.getUTCMonth(), this.date.getUTCDate())).valueOf(),\n\t\t\ttoday = new Date();\n\t\t\tthis.setTitle('.datetimepicker-days', dates[this.language].months[month] + ' ' + year);\n\t\t\tif (this.formatViewType == 'time') {\n\t\t\t\tvar formatted = this.getFormattedDate();\n\t\t\t\tthis.setTitle('.datetimepicker-hours', formatted);\n\t\t\t\tthis.setTitle('.datetimepicker-minutes', formatted);\n\t\t\t} else {\n\t\t\t\tthis.setTitle('.datetimepicker-hours', dayMonth + ' ' + dates[this.language].months[month] + ' ' + year);\n\t\t\t\tthis.setTitle('.datetimepicker-minutes', dayMonth + ' ' + dates[this.language].months[month] + ' ' + year);\n\t\t\t}\n\t\t\tthis.picker.find('tfoot th.today').text(dates[this.language].today || dates['en'].today).toggle(this.todayBtn !== false);\n\t\t\tthis.picker.find('tfoot th.clear').text(dates[this.language].clear || dates['en'].clear).toggle(this.clearBtn !== false);\n\t\t\tthis.updateNavArrows();\n\t\t\tthis.fillMonths();\n\t\t\t/*var prevMonth = UTCDate(year, month, 0,0,0,0,0);\n\t\tprevMonth.setUTCDate(prevMonth.getDate() - (prevMonth.getUTCDay() - this.weekStart + 7)%7);*/\n\t\t\tvar prevMonth = UTCDate(year, month - 1, 28, 0, 0, 0, 0),\n\t\t\tday = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());\n\t\t\tprevMonth.setUTCDate(day);\n\t\t\tprevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7) % 7);\n\t\t\tvar nextMonth = new Date(prevMonth);\n\t\t\tnextMonth.setUTCDate(nextMonth.getUTCDate() + 42);\n\t\t\tnextMonth = nextMonth.valueOf();\n\t\t\tvar html = [];\n\t\t\tvar clsName;\n\t\t\twhile (prevMonth.valueOf() < nextMonth) {\n\t\t\t\tif (prevMonth.getUTCDay() == this.weekStart) {\n\t\t\t\t\thtml.push('<tr>');\n\t\t\t\t}\n\t\t\t\tclsName = '';\n\t\t\t\tif (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {\n\t\t\t\t\tclsName += ' old';\n\t\t\t\t} else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {\n\t\t\t\t\tclsName += ' new';\n\t\t\t\t}\n\t\t\t\t// Compare internal UTC date with local today, not UTC today\n\t\t\t\tif (this.todayHighlight && prevMonth.getUTCFullYear() == today.getFullYear() && prevMonth.getUTCMonth() == today.getMonth() && prevMonth.getUTCDate() == today.getDate()) {\n\t\t\t\t\tclsName += ' today';\n\t\t\t\t}\n\t\t\t\tif (prevMonth.valueOf() == currentDate) {\n\t\t\t\t\tclsName += ' active';\n\t\t\t\t}\n\t\t\t\tif ((prevMonth.valueOf() + 86400000) <= this.startDate || prevMonth.valueOf() > this.endDate || $.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1 || $.inArray(prevMonth.toDateString(), this.datesDisabled) !== -1) {\n\t\t\t\t\tclsName += ' disabled';\n\t\t\t\t}\n\t\t\t\thtml.push('<td class=\"day' + clsName + '\">' + prevMonth.getUTCDate() + '</td>');\n\t\t\t\tif (prevMonth.getUTCDay() == this.weekEnd) {\n\t\t\t\t\thtml.push('</tr>');\n\t\t\t\t}\n\t\t\t\tprevMonth.setUTCDate(prevMonth.getUTCDate() + 1);\n\t\t\t}\n\t\t\tthis.picker.find('.datetimepicker-days tbody').empty().append(html.join(''));\n\n\t\t\thtml = [];\n\t\t\tvar txt = '',\n\t\t\tmeridian = '',\n\t\t\tmeridianOld = '';\n\t\t\tvar hoursDisabled = this.hoursDisabled || [];\n\t\t\tfor (var i = 0; i < 24; i++) {\n\t\t\t\tif (hoursDisabled.indexOf(i) !== -1) continue;\n\t\t\t\tvar actual = UTCDate(year, month, dayMonth, i);\n\t\t\t\tclsName = '';\n\t\t\t\t// We want the previous hour for the startDate\n\t\t\t\tif ((actual.valueOf() + 3600000) <= this.startDate || actual.valueOf() > this.endDate) {\n\t\t\t\t\tclsName += ' disabled';\n\t\t\t\t} else if (hours == i) {\n\t\t\t\t\tclsName += ' active';\n\t\t\t\t}\n\t\t\t\tif (this.showMeridian && dates[this.language].meridiem.length == 2) {\n\t\t\t\t\tmeridian = (i < 12 ? dates[this.language].meridiem[0] : dates[this.language].meridiem[1]);\n\t\t\t\t\tif (meridian != meridianOld) {\n\t\t\t\t\t\tif (meridianOld != '') {\n\t\t\t\t\t\t\thtml.push('</fieldset>');\n\t\t\t\t\t\t}\n\t\t\t\t\t\thtml.push('<fieldset class=\"hour\"><legend>' + meridian.toUpperCase() + '</legend>');\n\t\t\t\t\t}\n\t\t\t\t\tmeridianOld = meridian;\n\t\t\t\t\ttxt = (i % 12 ? i % 12 : 12);\n\t\t\t\t\thtml.push('<span class=\"hour' + clsName + ' hour_' + (i < 12 ? 'am': 'pm') + '\">' + txt + '</span>');\n\t\t\t\t\tif (i == 23) {\n\t\t\t\t\t\thtml.push('</fieldset>');\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttxt = i + ':00';\n\t\t\t\t\thtml.push('<span class=\"hour' + clsName + '\">' + txt + '</span>');\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.picker.find('.datetimepicker-hours td').html(html.join(''));\n\n\t\t\thtml = [];\n\t\t\ttxt = '',\n\t\t\tmeridian = '',\n\t\t\tmeridianOld = '';\n\t\t\tvar minutesDisabled = this.minutesDisabled || [];\n\t\t\tfor (var i = 0; i < 60; i += this.minuteStep) {\n\t\t\t\tif (minutesDisabled.indexOf(i) !== -1) continue;\n\t\t\t\tvar actual = UTCDate(year, month, dayMonth, hours, i, 0);\n\t\t\t\tclsName = '';\n\t\t\t\tif (actual.valueOf() < this.startDate || actual.valueOf() > this.endDate) {\n\t\t\t\t\tclsName += ' disabled';\n\t\t\t\t} else if (Math.floor(minutes / this.minuteStep) == Math.floor(i / this.minuteStep)) {\n\t\t\t\t\tclsName += ' active';\n\t\t\t\t}\n\t\t\t\tif (this.showMeridian && dates[this.language].meridiem.length == 2) {\n\t\t\t\t\tmeridian = (hours < 12 ? dates[this.language].meridiem[0] : dates[this.language].meridiem[1]);\n\t\t\t\t\tif (meridian != meridianOld) {\n\t\t\t\t\t\tif (meridianOld != '') {\n\t\t\t\t\t\t\thtml.push('</fieldset>');\n\t\t\t\t\t\t}\n\t\t\t\t\t\thtml.push('<fieldset class=\"minute\"><legend>' + meridian.toUpperCase() + '</legend>');\n\t\t\t\t\t}\n\t\t\t\t\tmeridianOld = meridian;\n\t\t\t\t\ttxt = (hours % 12 ? hours % 12 : 12);\n\t\t\t\t\t//html.push('<span class=\"minute'+clsName+' minute_'+(hours<12?'am':'pm')+'\">'+txt+'</span>');\n\t\t\t\t\thtml.push('<span class=\"minute' + clsName + '\">' + txt + ':' + (i < 10 ? '0' + i: i) + '</span>');\n\t\t\t\t\tif (i == 59) {\n\t\t\t\t\t\thtml.push('</fieldset>');\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttxt = i + ':00';\n\t\t\t\t\t//html.push('<span class=\"hour'+clsName+'\">'+txt+'</span>');\n\t\t\t\t\thtml.push('<span class=\"minute' + clsName + '\">' + hours + ':' + (i < 10 ? '0' + i: i) + '</span>');\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.picker.find('.datetimepicker-minutes td').html(html.join(''));\n\n\t\t\tvar currentYear = this.date.getUTCFullYear();\n\t\t\tvar months = this.setTitle('.datetimepicker-months', year).end().find('span').removeClass('active');\n\t\t\tif (currentYear == year) {\n\t\t\t\t// getUTCMonths() returns 0 based, and we need to select the next one\n\t\t\t\t// To cater bootstrap 2 we don't need to select the next one\n\t\t\t\tvar offset = months.length - 12;\n\t\t\t\tmonths.eq(this.date.getUTCMonth() + offset).addClass('active');\n\t\t\t}\n\t\t\tif (year < startYear || year > endYear) {\n\t\t\t\tmonths.addClass('disabled');\n\t\t\t}\n\t\t\tif (year == startYear) {\n\t\t\t\tmonths.slice(0, startMonth).addClass('disabled');\n\t\t\t}\n\t\t\tif (year == endYear) {\n\t\t\t\tmonths.slice(endMonth).addClass('disabled');\n\t\t\t}\n\n\t\t\thtml = '';\n\t\t\tyear = parseInt(year / 10, 10) * 10;\n\t\t\tvar yearCont = this.setTitle('.datetimepicker-years', year + '-' + (year + 9)).end().find('td');\n\t\t\tyear -= 1;\n\t\t\tfor (var i = -1; i < 11; i++) {\n\t\t\t\thtml += '<span class=\"year' + (i == -1 || i == 10 ? ' old': '') + (currentYear == year ? ' active': '') + (year < startYear || year > endYear ? ' disabled': '') + '\">' + year + '</span>';\n\t\t\t\tyear += 1;\n\t\t\t}\n\t\t\tyearCont.html(html);\n\t\t\tthis.place();\n\t\t},\n\n\t\tupdateNavArrows: function() {\n\t\t\tvar d = new Date(this.viewDate),\n\t\t\tyear = d.getUTCFullYear(),\n\t\t\tmonth = d.getUTCMonth(),\n\t\t\tday = d.getUTCDate(),\n\t\t\thour = d.getUTCHours();\n\t\t\tswitch (this.viewMode) {\n\t\t\tcase 0:\n\t\t\t\tif (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth() && day <= this.startDate.getUTCDate() && hour <= this.startDate.getUTCHours()) {\n\t\t\t\t\tthis.picker.find('.prev').css({\n\t\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthis.picker.find('.prev').css({\n\t\t\t\t\t\tvisibility: 'visible'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth() && day >= this.endDate.getUTCDate() && hour >= this.endDate.getUTCHours()) {\n\t\t\t\t\tthis.picker.find('.next').css({\n\t\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthis.picker.find('.next').css({\n\t\t\t\t\t\tvisibility: 'visible'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tif (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth() && day <= this.startDate.getUTCDate()) {\n\t\t\t\t\tthis.picker.find('.prev').css({\n\t\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthis.picker.find('.prev').css({\n\t\t\t\t\t\tvisibility: 'visible'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth() && day >= this.endDate.getUTCDate()) {\n\t\t\t\t\tthis.picker.find('.next').css({\n\t\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthis.picker.find('.next').css({\n\t\t\t\t\t\tvisibility: 'visible'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tif (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {\n\t\t\t\t\tthis.picker.find('.prev').css({\n\t\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthis.picker.find('.prev').css({\n\t\t\t\t\t\tvisibility: 'visible'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {\n\t\t\t\t\tthis.picker.find('.next').css({\n\t\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthis.picker.find('.next').css({\n\t\t\t\t\t\tvisibility: 'visible'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\tcase 4:\n\t\t\t\tif (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {\n\t\t\t\t\tthis.picker.find('.prev').css({\n\t\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthis.picker.find('.prev').css({\n\t\t\t\t\t\tvisibility: 'visible'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {\n\t\t\t\t\tthis.picker.find('.next').css({\n\t\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthis.picker.find('.next').css({\n\t\t\t\t\t\tvisibility: 'visible'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t},\n\n\t\tmousewheel: function(e) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tif (this.wheelPause) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.wheelPause = true;\n\t\t\tvar originalEvent = e.originalEvent;\n\t\t\tvar delta = originalEvent.wheelDelta;\n\t\t\tvar mode = delta > 0 ? 1 : (delta === 0) ? 0 : -1;\n\t\t\tif (this.wheelViewModeNavigationInverseDirection) {\n\t\t\t\tmode = -mode;\n\t\t\t}\n\n\t\t\tthis.showMode(mode);\n\t\t\tsetTimeout($.proxy(function() {\n\t\t\t\tthis.wheelPause = false\n\t\t\t},\n\t\t\tthis), this.wheelViewModeNavigationDelay);\n\t\t},\n\n\t\tclick: function(e) {\n\t\t\te.stopPropagation();\n\t\t\te.preventDefault();\n\t\t\tvar target = $(e.target).closest('span, td, th, legend');\n\t\t\tif (target.is('.' + this.icontype)) {\n\t\t\t\ttarget = $(target).parent().closest('span, td, th, legend');\n\t\t\t}\n\t\t\tif (target.length == 1) {\n\t\t\t\tif (target.is('.disabled')) {\n\t\t\t\t\tthis.element.trigger({\n\t\t\t\t\t\ttype: 'outOfRange',\n\t\t\t\t\t\tdate: this.viewDate,\n\t\t\t\t\t\tstartDate: this.startDate,\n\t\t\t\t\t\tendDate: this.endDate\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tswitch (target[0].nodeName.toLowerCase()) {\n\t\t\t\tcase 'th':\n\t\t\t\t\tswitch (target[0].className) {\n\t\t\t\t\tcase 'switch':\n\t\t\t\t\t\tthis.showMode(1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'prev':\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tvar dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);\n\t\t\t\t\t\tswitch (this.viewMode) {\n\t\t\t\t\t\tcase 0:\n\t\t\t\t\t\t\tthis.viewDate = this.moveHour(this.viewDate, dir);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 1:\n\t\t\t\t\t\t\tthis.viewDate = this.moveDate(this.viewDate, dir);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 2:\n\t\t\t\t\t\t\tthis.viewDate = this.moveMonth(this.viewDate, dir);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 3:\n\t\t\t\t\t\tcase 4:\n\t\t\t\t\t\t\tthis.viewDate = this.moveYear(this.viewDate, dir);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.fill();\n\t\t\t\t\t\tthis.element.trigger({\n\t\t\t\t\t\t\ttype: target[0].className + ':' + this.convertViewModeText(this.viewMode),\n\t\t\t\t\t\t\tdate: this.viewDate,\n\t\t\t\t\t\t\tstartDate: this.startDate,\n\t\t\t\t\t\t\tendDate: this.endDate\n\t\t\t\t\t\t});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'clear':\n\t\t\t\t\t\tthis.reset();\n\t\t\t\t\t\tif (this.autoclose) {\n\t\t\t\t\t\t\tthis.hide();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'today':\n\t\t\t\t\t\tvar date = new Date();\n\t\t\t\t\t\tdate = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), 0);\n\n\t\t\t\t\t\t// Respect startDate and endDate.\n\t\t\t\t\t\tif (date < this.startDate) date = this.startDate;\n\t\t\t\t\t\telse if (date > this.endDate) date = this.endDate;\n\n\t\t\t\t\t\tthis.viewMode = this.startViewMode;\n\t\t\t\t\t\tthis.showMode(0);\n\t\t\t\t\t\tthis._setDate(date);\n\t\t\t\t\t\tthis.fill();\n\t\t\t\t\t\tif (this.autoclose) {\n\t\t\t\t\t\t\tthis.hide();\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\tbreak;\n\t\t\t\tcase 'span':\n\t\t\t\t\tif (!target.is('.disabled')) {\n\t\t\t\t\t\tvar year = this.viewDate.getUTCFullYear(),\n\t\t\t\t\t\tmonth = this.viewDate.getUTCMonth(),\n\t\t\t\t\t\tday = this.viewDate.getUTCDate(),\n\t\t\t\t\t\thours = this.viewDate.getUTCHours(),\n\t\t\t\t\t\tminutes = this.viewDate.getUTCMinutes(),\n\t\t\t\t\t\tseconds = this.viewDate.getUTCSeconds();\n\n\t\t\t\t\t\tif (target.is('.month')) {\n\t\t\t\t\t\t\tthis.viewDate.setUTCDate(1);\n\t\t\t\t\t\t\tmonth = target.parent().find('span').index(target);\n\t\t\t\t\t\t\tday = this.viewDate.getUTCDate();\n\t\t\t\t\t\t\tthis.viewDate.setUTCMonth(month);\n\t\t\t\t\t\t\tthis.element.trigger({\n\t\t\t\t\t\t\t\ttype: 'changeMonth',\n\t\t\t\t\t\t\t\tdate: this.viewDate\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (this.viewSelect >= 3) {\n\t\t\t\t\t\t\t\tthis._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (target.is('.year')) {\n\t\t\t\t\t\t\tthis.viewDate.setUTCDate(1);\n\t\t\t\t\t\t\tyear = parseInt(target.text(), 10) || 0;\n\t\t\t\t\t\t\tthis.viewDate.setUTCFullYear(year);\n\t\t\t\t\t\t\tthis.element.trigger({\n\t\t\t\t\t\t\t\ttype: 'changeYear',\n\t\t\t\t\t\t\t\tdate: this.viewDate\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (this.viewSelect >= 4) {\n\t\t\t\t\t\t\t\tthis._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (target.is('.hour')) {\n\t\t\t\t\t\t\thours = parseInt(target.text(), 10) || 0;\n\t\t\t\t\t\t\tif (target.hasClass('hour_am') || target.hasClass('hour_pm')) {\n\t\t\t\t\t\t\t\tif (hours == 12 && target.hasClass('hour_am')) {\n\t\t\t\t\t\t\t\t\thours = 0;\n\t\t\t\t\t\t\t\t} else if (hours != 12 && target.hasClass('hour_pm')) {\n\t\t\t\t\t\t\t\t\thours += 12;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis.viewDate.setUTCHours(hours);\n\t\t\t\t\t\t\tthis.element.trigger({\n\t\t\t\t\t\t\t\ttype: 'changeHour',\n\t\t\t\t\t\t\t\tdate: this.viewDate\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (this.viewSelect >= 1) {\n\t\t\t\t\t\t\t\tthis._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (target.is('.minute')) {\n\t\t\t\t\t\t\tminutes = parseInt(target.text().substr(target.text().indexOf(':') + 1), 10) || 0;\n\t\t\t\t\t\t\tthis.viewDate.setUTCMinutes(minutes);\n\t\t\t\t\t\t\tthis.element.trigger({\n\t\t\t\t\t\t\t\ttype: 'changeMinute',\n\t\t\t\t\t\t\t\tdate: this.viewDate\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (this.viewSelect >= 0) {\n\t\t\t\t\t\t\t\tthis._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (this.viewMode != 0) {\n\t\t\t\t\t\t\tvar oldViewMode = this.viewMode;\n\t\t\t\t\t\t\tthis.showMode( - 1);\n\t\t\t\t\t\t\tthis.fill();\n\t\t\t\t\t\t\tif (oldViewMode == this.viewMode && this.autoclose) {\n\t\t\t\t\t\t\t\tthis.hide();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.fill();\n\t\t\t\t\t\t\tif (this.autoclose) {\n\t\t\t\t\t\t\t\tthis.hide();\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\tcase 'td':\n\t\t\t\t\tif (target.is('.day') && !target.is('.disabled')) {\n\t\t\t\t\t\tvar day = parseInt(target.text(), 10) || 1;\n\t\t\t\t\t\tvar year = this.viewDate.getUTCFullYear(),\n\t\t\t\t\t\tmonth = this.viewDate.getUTCMonth(),\n\t\t\t\t\t\thours = this.viewDate.getUTCHours(),\n\t\t\t\t\t\tminutes = this.viewDate.getUTCMinutes(),\n\t\t\t\t\t\tseconds = this.viewDate.getUTCSeconds();\n\t\t\t\t\t\tif (target.is('.old')) {\n\t\t\t\t\t\t\tif (month === 0) {\n\t\t\t\t\t\t\t\tmonth = 11;\n\t\t\t\t\t\t\t\tyear -= 1;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tmonth -= 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (target.is('.new')) {\n\t\t\t\t\t\t\tif (month == 11) {\n\t\t\t\t\t\t\t\tmonth = 0;\n\t\t\t\t\t\t\t\tyear += 1;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tmonth += 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.viewDate.setUTCFullYear(year);\n\t\t\t\t\t\tthis.viewDate.setUTCMonth(month, day);\n\t\t\t\t\t\tthis.element.trigger({\n\t\t\t\t\t\t\ttype: 'changeDay',\n\t\t\t\t\t\t\tdate: this.viewDate\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (this.viewSelect >= 2) {\n\t\t\t\t\t\t\tthis._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tvar oldViewMode = this.viewMode;\n\t\t\t\t\tthis.showMode( - 1);\n\t\t\t\t\tthis.fill();\n\t\t\t\t\tif (oldViewMode == this.viewMode && this.autoclose) {\n\t\t\t\t\t\tthis.hide();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t_setDate: function(date, which) {\n\t\t\tif (!which || which == 'date') this.date = date;\n\t\t\tif (!which || which == 'view') this.viewDate = date;\n\t\t\tthis.fill();\n\t\t\tthis.setValue();\n\t\t\tvar element;\n\t\t\tif (this.isInput) {\n\t\t\t\telement = this.element;\n\t\t\t} else if (this.component) {\n\t\t\t\telement = this.element.find('input');\n\t\t\t}\n\t\t\tif (element) {\n\t\t\t\telement.change();\n\t\t\t\tif (this.autoclose && (!which || which == 'date')) {\n\t\t\t\t\t//this.hide();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.element.trigger({\n\t\t\t\ttype: 'changeDate',\n\t\t\t\tdate: this.getDate()\n\t\t\t});\n\t\t\tif (date == null) this.date = this.viewDate;\n\t\t},\n\n\t\tmoveMinute: function(date, dir) {\n\t\t\tif (!dir) return date;\n\t\t\tvar new_date = new Date(date.valueOf());\n\t\t\t//dir = dir > 0 ? 1 : -1;\n\t\t\tnew_date.setUTCMinutes(new_date.getUTCMinutes() + (dir * this.minuteStep));\n\t\t\treturn new_date;\n\t\t},\n\n\t\tmoveHour: function(date, dir) {\n\t\t\tif (!dir) return date;\n\t\t\tvar new_date = new Date(date.valueOf());\n\t\t\t//dir = dir > 0 ? 1 : -1;\n\t\t\tnew_date.setUTCHours(new_date.getUTCHours() + dir);\n\t\t\treturn new_date;\n\t\t},\n\n\t\tmoveDate: function(date, dir) {\n\t\t\tif (!dir) return date;\n\t\t\tvar new_date = new Date(date.valueOf());\n\t\t\t//dir = dir > 0 ? 1 : -1;\n\t\t\tnew_date.setUTCDate(new_date.getUTCDate() + dir);\n\t\t\treturn new_date;\n\t\t},\n\n\t\tmoveMonth: function(date, dir) {\n\t\t\tif (!dir) return date;\n\t\t\tvar new_date = new Date(date.valueOf()),\n\t\t\tday = new_date.getUTCDate(),\n\t\t\tmonth = new_date.getUTCMonth(),\n\t\t\tmag = Math.abs(dir),\n\t\t\tnew_month,\n\t\t\ttest;\n\t\t\tdir = dir > 0 ? 1 : -1;\n\t\t\tif (mag == 1) {\n\t\t\t\ttest = dir == -1\n\t\t\t\t// If going back one month, make sure month is not current month\n\t\t\t\t// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)\n\t\t\t\t?\n\t\t\t\tfunction() {\n\t\t\t\t\treturn new_date.getUTCMonth() == month;\n\t\t\t\t}\n\t\t\t\t// If going forward one month, make sure month is as expected\n\t\t\t\t// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)\n\t\t\t\t: function() {\n\t\t\t\t\treturn new_date.getUTCMonth() != new_month;\n\t\t\t\t};\n\t\t\t\tnew_month = month + dir;\n\t\t\t\tnew_date.setUTCMonth(new_month);\n\t\t\t\t// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11\n\t\t\t\tif (new_month < 0 || new_month > 11) new_month = (new_month + 12) % 12;\n\t\t\t} else {\n\t\t\t\t// For magnitudes >1, move one month at a time...\n\t\t\t\tfor (var i = 0; i < mag; i++)\n\t\t\t\t// ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...\n\t\t\t\tnew_date = this.moveMonth(new_date, dir);\n\t\t\t\t// ...then reset the day, keeping it in the new month\n\t\t\t\tnew_month = new_date.getUTCMonth();\n\t\t\t\tnew_date.setUTCDate(day);\n\t\t\t\ttest = function() {\n\t\t\t\t\treturn new_month != new_date.getUTCMonth();\n\t\t\t\t};\n\t\t\t}\n\t\t\t// Common date-resetting loop -- if date is beyond end of month, make it\n\t\t\t// end of month\n\t\t\twhile (test()) {\n\t\t\t\tnew_date.setUTCDate(--day);\n\t\t\t\tnew_date.setUTCMonth(new_month);\n\t\t\t}\n\t\t\treturn new_date;\n\t\t},\n\n\t\tmoveYear: function(date, dir) {\n\t\t\treturn this.moveMonth(date, dir * 12);\n\t\t},\n\n\t\tdateWithinRange: function(date) {\n\t\t\treturn date >= this.startDate && date <= this.endDate;\n\t\t},\n\n\t\tkeydown: function(e) {\n\t\t\tif (this.picker.is(':not(:visible)')) {\n\t\t\t\tif (e.keyCode == 27) // allow escape to hide and re-show picker\n\t\t\t\tthis.show();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar dateChanged = false,\n\t\t\tdir, day, month, newDate, newViewDate;\n\t\t\tswitch (e.keyCode) {\n\t\t\tcase 27:\n\t\t\t\t// escape\n\t\t\t\tthis.hide();\n\t\t\t\te.preventDefault();\n\t\t\t\tbreak;\n\t\t\tcase 37:\n\t\t\t\t// left\n\t\t\tcase 39:\n\t\t\t\t// right\n\t\t\t\tif (!this.keyboardNavigation) break;\n\t\t\t\tdir = e.keyCode == 37 ? -1 : 1;\n\t\t\t\tviewMode = this.viewMode;\n\t\t\t\tif (e.ctrlKey) {\n\t\t\t\t\tviewMode += 2;\n\t\t\t\t} else if (e.shiftKey) {\n\t\t\t\t\tviewMode += 1;\n\t\t\t\t}\n\t\t\t\tif (viewMode == 4) {\n\t\t\t\t\tnewDate = this.moveYear(this.date, dir);\n\t\t\t\t\tnewViewDate = this.moveYear(this.viewDate, dir);\n\t\t\t\t} else if (viewMode == 3) {\n\t\t\t\t\tnewDate = this.moveMonth(this.date, dir);\n\t\t\t\t\tnewViewDate = this.moveMonth(this.viewDate, dir);\n\t\t\t\t} else if (viewMode == 2) {\n\t\t\t\t\tnewDate = this.moveDate(this.date, dir);\n\t\t\t\t\tnewViewDate = this.moveDate(this.viewDate, dir);\n\t\t\t\t} else if (viewMode == 1) {\n\t\t\t\t\tnewDate = this.moveHour(this.date, dir);\n\t\t\t\t\tnewViewDate = this.moveHour(this.viewDate, dir);\n\t\t\t\t} else if (viewMode == 0) {\n\t\t\t\t\tnewDate = this.moveMinute(this.date, dir);\n\t\t\t\t\tnewViewDate = this.moveMinute(this.viewDate, dir);\n\t\t\t\t}\n\t\t\t\tif (this.dateWithinRange(newDate)) {\n\t\t\t\t\tthis.date = newDate;\n\t\t\t\t\tthis.viewDate = newViewDate;\n\t\t\t\t\tthis.setValue();\n\t\t\t\t\tthis.update();\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tdateChanged = true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 38:\n\t\t\t\t// up\n\t\t\tcase 40:\n\t\t\t\t// down\n\t\t\t\tif (!this.keyboardNavigation) break;\n\t\t\t\tdir = e.keyCode == 38 ? -1 : 1;\n\t\t\t\tviewMode = this.viewMode;\n\t\t\t\tif (e.ctrlKey) {\n\t\t\t\t\tviewMode += 2;\n\t\t\t\t} else if (e.shiftKey) {\n\t\t\t\t\tviewMode += 1;\n\t\t\t\t}\n\t\t\t\tif (viewMode == 4) {\n\t\t\t\t\tnewDate = this.moveYear(this.date, dir);\n\t\t\t\t\tnewViewDate = this.moveYear(this.viewDate, dir);\n\t\t\t\t} else if (viewMode == 3) {\n\t\t\t\t\tnewDate = this.moveMonth(this.date, dir);\n\t\t\t\t\tnewViewDate = this.moveMonth(this.viewDate, dir);\n\t\t\t\t} else if (viewMode == 2) {\n\t\t\t\t\tnewDate = this.moveDate(this.date, dir * 7);\n\t\t\t\t\tnewViewDate = this.moveDate(this.viewDate, dir * 7);\n\t\t\t\t} else if (viewMode == 1) {\n\t\t\t\t\tif (this.showMeridian) {\n\t\t\t\t\t\tnewDate = this.moveHour(this.date, dir * 6);\n\t\t\t\t\t\tnewViewDate = this.moveHour(this.viewDate, dir * 6);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnewDate = this.moveHour(this.date, dir * 4);\n\t\t\t\t\t\tnewViewDate = this.moveHour(this.viewDate, dir * 4);\n\t\t\t\t\t}\n\t\t\t\t} else if (viewMode == 0) {\n\t\t\t\t\tnewDate = this.moveMinute(this.date, dir * 4);\n\t\t\t\t\tnewViewDate = this.moveMinute(this.viewDate, dir * 4);\n\t\t\t\t}\n\t\t\t\tif (this.dateWithinRange(newDate)) {\n\t\t\t\t\tthis.date = newDate;\n\t\t\t\t\tthis.viewDate = newViewDate;\n\t\t\t\t\tthis.setValue();\n\t\t\t\t\tthis.update();\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tdateChanged = true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 13:\n\t\t\t\t// enter\n\t\t\t\tif (this.viewMode != 0) {\n\t\t\t\t\tvar oldViewMode = this.viewMode;\n\t\t\t\t\tthis.showMode( - 1);\n\t\t\t\t\tthis.fill();\n\t\t\t\t\tif (oldViewMode == this.viewMode && this.autoclose) {\n\t\t\t\t\t\tthis.hide();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.fill();\n\t\t\t\t\tif (this.autoclose) {\n\t\t\t\t\t\tthis.hide();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\te.preventDefault();\n\t\t\t\tbreak;\n\t\t\tcase 9:\n\t\t\t\t// tab\n\t\t\t\tthis.hide();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (dateChanged) {\n\t\t\t\tvar element;\n\t\t\t\tif (this.isInput) {\n\t\t\t\t\telement = this.element;\n\t\t\t\t} else if (this.component) {\n\t\t\t\t\telement = this.element.find('input');\n\t\t\t\t}\n\t\t\t\tif (element) {\n\t\t\t\t\telement.change();\n\t\t\t\t}\n\t\t\t\tthis.element.trigger({\n\t\t\t\t\ttype: 'changeDate',\n\t\t\t\t\tdate: this.getDate()\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\n\t\tshowMode: function(dir) {\n\t\t\tif (dir) {\n\t\t\t\tvar newViewMode = Math.max(0, Math.min(DPGlobal.modes.length - 1, this.viewMode + dir));\n\t\t\t\tif (newViewMode >= this.minView && newViewMode <= this.maxView) {\n\t\t\t\t\tthis.element.trigger({\n\t\t\t\t\t\ttype: 'changeMode',\n\t\t\t\t\t\tdate: this.viewDate,\n\t\t\t\t\t\toldViewMode: this.viewMode,\n\t\t\t\t\t\tnewViewMode: newViewMode\n\t\t\t\t\t});\n\t\t\t\t\tthis.viewMode = newViewMode;\n\t\t\t\t}\n\t\t\t}\n\t\t\t/*\n\tvitalets: fixing bug of very special conditions:\n\tjquery 1.7.1 + webkit + show inline datetimepicker in bootstrap popover.\n\tMethod show() does not set display css correctly and datetimepicker is not shown.\n\tChanged to .css('display', 'block') solve the problem.\n\tSee https://github.com/vitalets/x-editable/issues/37\n\t\n\tIn jquery 1.7.2+ everything works fine.\n\t*/\n\t\t\t//this.picker.find('>div').hide().filter('.datetimepicker-'+DPGlobal.modes[this.viewMode].clsName).show();\n\t\t\tthis.picker.find('>div').hide().filter('.datetimepicker-' + DPGlobal.modes[this.viewMode].clsName).css('display', 'block');\n\t\t\tthis.updateNavArrows();\n\t\t},\n\n\t\treset: function(e) {\n\t\t\tthis._setDate(null, 'date');\n\t\t},\n\n\t\tconvertViewModeText: function(viewMode) {\n\t\t\tswitch (viewMode) {\n\t\t\tcase 4:\n\t\t\t\treturn 'decade';\n\t\t\tcase 3:\n\t\t\t\treturn 'year';\n\t\t\tcase 2:\n\t\t\t\treturn 'month';\n\t\t\tcase 1:\n\t\t\t\treturn 'day';\n\t\t\tcase 0:\n\t\t\t\treturn 'hour';\n\t\t\t}\n\t\t}\n\t};\n\n\tvar old = $.fn.datetimepicker;\n\t$.fn.datetimepicker = function(option) {\n\t\tvar args = Array.apply(null, arguments);\n\t\targs.shift();\n\t\tvar internal_return;\n\t\tthis.each(function() {\n\t\t\tvar $this = $(this),\n\t\t\tdata = $this.data('datetimepicker'),\n\t\t\toptions = typeof option == 'object' && option;\n\t\t\tif (!data) {\n\t\t\t\t$this.data('datetimepicker', (data = new Datetimepicker(this, $.extend({},\n\t\t\t\t$.fn.datetimepicker.defaults, options))));\n\t\t\t}\n\t\t\tif (typeof option == 'string' && typeof data[option] == 'function') {\n\t\t\t\tinternal_return = data[option].apply(data, args);\n\t\t\t\tif (internal_return !== undefined) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tif (internal_return !== undefined) return internal_return;\n\t\telse return this;\n\t};\n\n\t$.fn.datetimepicker.defaults = {};\n\t$.fn.datetimepicker.Constructor = Datetimepicker;\n\tvar dates = $.fn.datetimepicker.dates = {\n\t\ten: {\n\t\t\tdays: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],\n\t\t\tdaysShort: ['日', '一', '二', '三', '四', '五', '六', '日'],\n\t\t\tdaysMin: ['日', '一', '二', '三', '四', '五', '六', '日'],\n\t\t\tmonths: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],\n\t\t\tmonthsShort: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n\t\t\tmeridiem: ['上午', '下午'],\n\t\t\tsuffix: ['st', 'nd', 'rd', 'th'],\n\t\t\ttoday: '今天',\n\t\t\tclear: '清空'\n\t\t}\n\t};\n\n\tvar DPGlobal = {\n\t\tmodes: [{\n\t\t\tclsName: 'minutes',\n\t\t\tnavFnc: 'Hours',\n\t\t\tnavStep: 1\n\t\t},\n\t\t{\n\t\t\tclsName: 'hours',\n\t\t\tnavFnc: 'Date',\n\t\t\tnavStep: 1\n\t\t},\n\t\t{\n\t\t\tclsName: 'days',\n\t\t\tnavFnc: 'Month',\n\t\t\tnavStep: 1\n\t\t},\n\t\t{\n\t\t\tclsName: 'months',\n\t\t\tnavFnc: 'FullYear',\n\t\t\tnavStep: 1\n\t\t},\n\t\t{\n\t\t\tclsName: 'years',\n\t\t\tnavFnc: 'FullYear',\n\t\t\tnavStep: 10\n\t\t}],\n\t\tisLeapYear: function(year) {\n\t\t\treturn (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))\n\t\t},\n\t\tgetDaysInMonth: function(year, month) {\n\t\t\treturn [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]\n\t\t},\n\t\tgetDefaultFormat: function(type, field) {\n\t\t\tif (type == 'standard') {\n\t\t\t\tif (field == 'input') return 'yyyy-mm-dd hh:ii';\n\t\t\t\telse return 'yyyy-mm-dd hh:ii:ss';\n\t\t\t} else if (type == 'php') {\n\t\t\t\tif (field == 'input') return 'Y-m-d H:i';\n\t\t\t\telse return 'Y-m-d H:i:s';\n\t\t\t} else {\n\t\t\t\tthrow new Error('Invalid format type.');\n\t\t\t}\n\t\t},\n\t\tvalidParts: function(type) {\n\t\t\tif (type == 'standard') {\n\t\t\t\treturn /t|hh?|HH?|p|P|z|Z|ii?|ss?|dd?|DD?|mm?|MM?|yy(?:yy)?/g;\n\t\t\t} else if (type == 'php') {\n\t\t\t\treturn /[dDjlNwzFmMnStyYaABgGhHis]/g;\n\t\t\t} else {\n\t\t\t\tthrow new Error('Invalid format type.');\n\t\t\t}\n\t\t},\n\t\tnonpunctuation: /[^ -\\/:-@\\[-`{-~\\t\\n\\rTZ]+/g,\n\t\tparseFormat: function(format, type) {\n\t\t\t// IE treats \\0 as a string end in inputs (truncating the value),\n\t\t\t// so it's a bad format delimiter, anyway\n\t\t\tvar separators = format.replace(this.validParts(type), '\\0').split('\\0'),\n\t\t\tparts = format.match(this.validParts(type));\n\t\t\tif (!separators || !separators.length || !parts || parts.length == 0) {\n\t\t\t\tthrow new Error('Invalid date format.');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tseparators: separators,\n\t\t\t\tparts: parts\n\t\t\t};\n\t\t},\n\t\tparseDate: function(date, format, language, type, timezone) {\n\t\t\tif (date instanceof Date) {\n\t\t\t\tvar dateUTC = new Date(date.valueOf() - date.getTimezoneOffset() * 60000);\n\t\t\t\tdateUTC.setMilliseconds(0);\n\t\t\t\treturn dateUTC;\n\t\t\t}\n\t\t\tif (/^\\d{4}\\-\\d{1,2}\\-\\d{1,2}$/.test(date)) {\n\t\t\t\tformat = this.parseFormat('yyyy-mm-dd', type);\n\t\t\t}\n\t\t\tif (/^\\d{4}\\-\\d{1,2}\\-\\d{1,2}[T ]\\d{1,2}\\:\\d{1,2}$/.test(date)) {\n\t\t\t\tformat = this.parseFormat('yyyy-mm-dd hh:ii', type);\n\t\t\t}\n\t\t\tif (/^\\d{4}\\-\\d{1,2}\\-\\d{1,2}[T ]\\d{1,2}\\:\\d{1,2}\\:\\d{1,2}[Z]{0,1}$/.test(date)) {\n\t\t\t\tformat = this.parseFormat('yyyy-mm-dd hh:ii:ss', type);\n\t\t\t}\n\t\t\tif (/^[-+]\\d+[dmwy]([\\s,]+[-+]\\d+[dmwy])*$/.test(date)) {\n\t\t\t\tvar part_re = /([-+]\\d+)([dmwy])/,\n\t\t\t\tparts = date.match(/([-+]\\d+)([dmwy])/g),\n\t\t\t\tpart,\n\t\t\t\tdir;\n\t\t\t\tdate = new Date();\n\t\t\t\tfor (var i = 0; i < parts.length; i++) {\n\t\t\t\t\tpart = part_re.exec(parts[i]);\n\t\t\t\t\tdir = parseInt(part[1]);\n\t\t\t\t\tswitch (part[2]) {\n\t\t\t\t\tcase 'd':\n\t\t\t\t\t\tdate.setUTCDate(date.getUTCDate() + dir);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'm':\n\t\t\t\t\t\tdate = Datetimepicker.prototype.moveMonth.call(Datetimepicker.prototype, date, dir);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'w':\n\t\t\t\t\t\tdate.setUTCDate(date.getUTCDate() + dir * 7);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'y':\n\t\t\t\t\t\tdate = Datetimepicker.prototype.moveYear.call(Datetimepicker.prototype, date, dir);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), 0);\n\t\t\t}\n\t\t\tvar parts = date && date.toString().match(this.nonpunctuation) || [],\n\t\t\tdate = new Date(0, 0, 0, 0, 0, 0, 0),\n\t\t\tparsed = {},\n\t\t\tsetters_order = ['hh', 'h', 'ii', 'i', 'ss', 's', 'yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'D', 'DD', 'd', 'dd', 'H', 'HH', 'p', 'P', 'z', 'Z'],\n\t\t\tsetters_map = {\n\t\t\t\thh: function(d, v) {\n\t\t\t\t\treturn d.setUTCHours(v);\n\t\t\t\t},\n\t\t\t\th: function(d, v) {\n\t\t\t\t\treturn d.setUTCHours(v);\n\t\t\t\t},\n\t\t\t\tHH: function(d, v) {\n\t\t\t\t\treturn d.setUTCHours(v == 12 ? 0 : v);\n\t\t\t\t},\n\t\t\t\tH: function(d, v) {\n\t\t\t\t\treturn d.setUTCHours(v == 12 ? 0 : v);\n\t\t\t\t},\n\t\t\t\tii: function(d, v) {\n\t\t\t\t\treturn d.setUTCMinutes(v);\n\t\t\t\t},\n\t\t\t\ti: function(d, v) {\n\t\t\t\t\treturn d.setUTCMinutes(v);\n\t\t\t\t},\n\t\t\t\tss: function(d, v) {\n\t\t\t\t\treturn d.setUTCSeconds(v);\n\t\t\t\t},\n\t\t\t\ts: function(d, v) {\n\t\t\t\t\treturn d.setUTCSeconds(v);\n\t\t\t\t},\n\t\t\t\tyyyy: function(d, v) {\n\t\t\t\t\treturn d.setUTCFullYear(v);\n\t\t\t\t},\n\t\t\t\tyy: function(d, v) {\n\t\t\t\t\treturn d.setUTCFullYear(2000 + v);\n\t\t\t\t},\n\t\t\t\tm: function(d, v) {\n\t\t\t\t\tv -= 1;\n\t\t\t\t\twhile (v < 0) v += 12;\n\t\t\t\t\tv %= 12;\n\t\t\t\t\td.setUTCMonth(v);\n\t\t\t\t\twhile (d.getUTCMonth() != v) if (isNaN(d.getUTCMonth())) return d;\n\t\t\t\t\telse d.setUTCDate(d.getUTCDate() - 1);\n\t\t\t\t\treturn d;\n\t\t\t\t},\n\t\t\t\td: function(d, v) {\n\t\t\t\t\treturn d.setUTCDate(v);\n\t\t\t\t},\n\t\t\t\tp: function(d, v) {\n\t\t\t\t\treturn d.setUTCHours(v == 1 ? d.getUTCHours() + 12 : d.getUTCHours());\n\t\t\t\t},\n\t\t\t\tz: function() {\n\t\t\t\t\treturn timezone\n\t\t\t\t}\n\t\t\t},\n\t\t\tval,\n\t\t\tfiltered,\n\t\t\tpart;\n\t\t\tsetters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];\n\t\t\tsetters_map['dd'] = setters_map['d'];\n\t\t\tsetters_map['P'] = setters_map['p'];\n\t\t\tsetters_map['Z'] = setters_map['z'];\n\t\t\tdate = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());\n\t\t\tif (parts.length == format.parts.length) {\n\t\t\t\tfor (var i = 0,\n\t\t\t\tcnt = format.parts.length; i < cnt; i++) {\n\t\t\t\t\tval = parseInt(parts[i], 10);\n\t\t\t\t\tpart = format.parts[i];\n\t\t\t\t\tif (isNaN(val)) {\n\t\t\t\t\t\tswitch (part) {\n\t\t\t\t\t\tcase 'MM':\n\t\t\t\t\t\t\tfiltered = $(dates[language].months).filter(function() {\n\t\t\t\t\t\t\t\tvar m = this.slice(0, parts[i].length),\n\t\t\t\t\t\t\t\tp = parts[i].slice(0, m.length);\n\t\t\t\t\t\t\t\treturn m == p;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tval = $.inArray(filtered[0], dates[language].months) + 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'M':\n\t\t\t\t\t\t\tfiltered = $(dates[language].monthsShort).filter(function() {\n\t\t\t\t\t\t\t\tvar m = this.slice(0, parts[i].length),\n\t\t\t\t\t\t\t\tp = parts[i].slice(0, m.length);\n\t\t\t\t\t\t\t\treturn m.toLowerCase() == p.toLowerCase();\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tval = $.inArray(filtered[0], dates[language].monthsShort) + 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'p':\n\t\t\t\t\t\tcase 'P':\n\t\t\t\t\t\t\tval = $.inArray(parts[i].toLowerCase(), dates[language].meridiem);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'z':\n\t\t\t\t\t\tcase 'Z':\n\t\t\t\t\t\t\ttimezone;\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\tparsed[part] = val;\n\t\t\t\t}\n\t\t\t\tfor (var i = 0,\n\t\t\t\ts; i < setters_order.length; i++) {\n\t\t\t\t\ts = setters_order[i];\n\t\t\t\t\tif (s in parsed && !isNaN(parsed[s])) setters_map[s](date, parsed[s])\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn date;\n\t\t},\n\t\tformatDate: function(date, format, language, type, timezone) {\n\t\t\tif (date == null) {\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tvar val;\n\t\t\tif (type == 'standard') {\n\t\t\t\tval = {\n\t\t\t\t\tt: date.getTime(),\n\t\t\t\t\t// year\n\t\t\t\t\tyy: date.getUTCFullYear().toString().substring(2),\n\t\t\t\t\tyyyy: date.getUTCFullYear(),\n\t\t\t\t\t// month\n\t\t\t\t\tm: date.getUTCMonth() + 1,\n\t\t\t\t\tM: dates[language].monthsShort[date.getUTCMonth()],\n\t\t\t\t\tMM: dates[language].months[date.getUTCMonth()],\n\t\t\t\t\t// day\n\t\t\t\t\td: date.getUTCDate(),\n\t\t\t\t\tD: dates[language].daysShort[date.getUTCDay()],\n\t\t\t\t\tDD: dates[language].days[date.getUTCDay()],\n\t\t\t\t\tp: (dates[language].meridiem.length == 2 ? dates[language].meridiem[date.getUTCHours() < 12 ? 0 : 1] : ''),\n\t\t\t\t\t// hour\n\t\t\t\t\th: date.getUTCHours(),\n\t\t\t\t\t// minute\n\t\t\t\t\ti: date.getUTCMinutes(),\n\t\t\t\t\t// second\n\t\t\t\t\ts: date.getUTCSeconds(),\n\t\t\t\t\t// timezone\n\t\t\t\t\tz: timezone\n\t\t\t\t};\n\n\t\t\t\tif (dates[language].meridiem.length == 2) {\n\t\t\t\t\tval.H = (val.h % 12 == 0 ? 12 : val.h % 12);\n\t\t\t\t} else {\n\t\t\t\t\tval.H = val.h;\n\t\t\t\t}\n\t\t\t\tval.HH = (val.H < 10 ? '0': '') + val.H;\n\t\t\t\tval.P = val.p.toUpperCase();\n\t\t\t\tval.Z = val.z;\n\t\t\t\tval.hh = (val.h < 10 ? '0': '') + val.h;\n\t\t\t\tval.ii = (val.i < 10 ? '0': '') + val.i;\n\t\t\t\tval.ss = (val.s < 10 ? '0': '') + val.s;\n\t\t\t\tval.dd = (val.d < 10 ? '0': '') + val.d;\n\t\t\t\tval.mm = (val.m < 10 ? '0': '') + val.m;\n\t\t\t} else if (type == 'php') {\n\t\t\t\t// php format\n\t\t\t\tval = {\n\t\t\t\t\t// year\n\t\t\t\t\ty: date.getUTCFullYear().toString().substring(2),\n\t\t\t\t\tY: date.getUTCFullYear(),\n\t\t\t\t\t// month\n\t\t\t\t\tF: dates[language].months[date.getUTCMonth()],\n\t\t\t\t\tM: dates[language].monthsShort[date.getUTCMonth()],\n\t\t\t\t\tn: date.getUTCMonth() + 1,\n\t\t\t\t\tt: DPGlobal.getDaysInMonth(date.getUTCFullYear(), date.getUTCMonth()),\n\t\t\t\t\t// day\n\t\t\t\t\tj: date.getUTCDate(),\n\t\t\t\t\tl: dates[language].days[date.getUTCDay()],\n\t\t\t\t\tD: dates[language].daysShort[date.getUTCDay()],\n\t\t\t\t\tw: date.getUTCDay(),\n\t\t\t\t\t// 0 -> 6\n\t\t\t\t\tN: (date.getUTCDay() == 0 ? 7 : date.getUTCDay()),\n\t\t\t\t\t// 1 -> 7\n\t\t\t\t\tS: (date.getUTCDate() % 10 <= dates[language].suffix.length ? dates[language].suffix[date.getUTCDate() % 10 - 1] : ''),\n\t\t\t\t\t// hour\n\t\t\t\t\ta: (dates[language].meridiem.length == 2 ? dates[language].meridiem[date.getUTCHours() < 12 ? 0 : 1] : ''),\n\t\t\t\t\tg: (date.getUTCHours() % 12 == 0 ? 12 : date.getUTCHours() % 12),\n\t\t\t\t\tG: date.getUTCHours(),\n\t\t\t\t\t// minute\n\t\t\t\t\ti: date.getUTCMinutes(),\n\t\t\t\t\t// second\n\t\t\t\t\ts: date.getUTCSeconds()\n\t\t\t\t};\n\t\t\t\tval.m = (val.n < 10 ? '0': '') + val.n;\n\t\t\t\tval.d = (val.j < 10 ? '0': '') + val.j;\n\t\t\t\tval.A = val.a.toString().toUpperCase();\n\t\t\t\tval.h = (val.g < 10 ? '0': '') + val.g;\n\t\t\t\tval.H = (val.G < 10 ? '0': '') + val.G;\n\t\t\t\tval.i = (val.i < 10 ? '0': '') + val.i;\n\t\t\t\tval.s = (val.s < 10 ? '0': '') + val.s;\n\t\t\t} else {\n\t\t\t\tthrow new Error('Invalid format type.');\n\t\t\t}\n\t\t\tvar date = [],\n\t\t\tseps = $.extend([], format.separators);\n\t\t\tfor (var i = 0,\n\t\t\tcnt = format.parts.length; i < cnt; i++) {\n\t\t\t\tif (seps.length) {\n\t\t\t\t\tdate.push(seps.shift());\n\t\t\t\t}\n\t\t\t\tdate.push(val[format.parts[i]]);\n\t\t\t}\n\t\t\tif (seps.length) {\n\t\t\t\tdate.push(seps.shift());\n\t\t\t}\n\t\t\treturn date.join('');\n\t\t},\n\t\tconvertViewMode: function(viewMode) {\n\t\t\tswitch (viewMode) {\n\t\t\tcase 4:\n\t\t\tcase 'decade':\n\t\t\t\tviewMode = 4;\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\tcase 'year':\n\t\t\t\tviewMode = 3;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\tcase 'month':\n\t\t\t\tviewMode = 2;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\tcase 'day':\n\t\t\t\tviewMode = 1;\n\t\t\t\tbreak;\n\t\t\tcase 0:\n\t\t\tcase 'hour':\n\t\t\t\tviewMode = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn viewMode;\n\t\t},\n\t\theadTemplate: '<thead>' + '<tr>' + '<th class=\"prev\"><i class=\"{iconType} {leftArrow}\"/></th>' + '<th colspan=\"5\" class=\"switch\"></th>' + '<th class=\"next\"><i class=\"{iconType} {rightArrow}\"/></th>' + '</tr>' + '</thead>',\n\t\theadTemplateV3: '<thead>' + '<tr>' + '<th class=\"prev\"><span class=\"{iconType} {leftArrow}\"></span> </th>' + '<th colspan=\"5\" class=\"switch\"></th>' + '<th class=\"next\"><span class=\"{iconType} {rightArrow}\"></span> </th>' + '</tr>' + '</thead>',\n\t\tcontTemplate: '<tbody><tr><td colspan=\"7\"></td></tr></tbody>',\n\t\tfootTemplate: '<tfoot>' + '<tr><th colspan=\"7\" class=\"today\"></th></tr>' + '<tr><th colspan=\"7\" class=\"clear\"></th></tr>' + '</tfoot>'\n\t};\n\tDPGlobal.template = '<div class=\"datetimepicker\">' + '<div class=\"datetimepicker-minutes\">' + '<table class=\" table-condensed\">' + DPGlobal.headTemplate + DPGlobal.contTemplate + DPGlobal.footTemplate + '</table>' + '</div>' + '<div class=\"datetimepicker-hours\">' + '<table class=\" table-condensed\">' + DPGlobal.headTemplate + DPGlobal.contTemplate + DPGlobal.footTemplate + '</table>' + '</div>' + '<div class=\"datetimepicker-days\">' + '<table class=\" table-condensed\">' + DPGlobal.headTemplate + '<tbody></tbody>' + DPGlobal.footTemplate + '</table>' + '</div>' + '<div class=\"datetimepicker-months\">' + '<table class=\"table-condensed\">' + DPGlobal.headTemplate + DPGlobal.contTemplate + DPGlobal.footTemplate + '</table>' + '</div>' + '<div class=\"datetimepicker-years\">' + '<table class=\"table-condensed\">' + DPGlobal.headTemplate + DPGlobal.contTemplate + DPGlobal.footTemplate + '</table>' + '</div>' + '</div>';\n\tDPGlobal.templateV3 = '<div class=\"datetimepicker\">' + '<div class=\"datetimepicker-minutes\">' + '<table class=\" table-condensed\">' + DPGlobal.headTemplateV3 + DPGlobal.contTemplate + DPGlobal.footTemplate + '</table>' + '</div>' + '<div class=\"datetimepicker-hours\">' + '<table class=\" table-condensed\">' + DPGlobal.headTemplateV3 + DPGlobal.contTemplate + DPGlobal.footTemplate + '</table>' + '</div>' + '<div class=\"datetimepicker-days\">' + '<table class=\" table-condensed\">' + DPGlobal.headTemplateV3 + '<tbody></tbody>' + DPGlobal.footTemplate + '</table>' + '</div>' + '<div class=\"datetimepicker-months\">' + '<table class=\"table-condensed\">' + DPGlobal.headTemplateV3 + DPGlobal.contTemplate + DPGlobal.footTemplate + '</table>' + '</div>' + '<div class=\"datetimepicker-years\">' + '<table class=\"table-condensed\">' + DPGlobal.headTemplateV3 + DPGlobal.contTemplate + DPGlobal.footTemplate + '</table>' + '</div>' + '</div>';\n\t$.fn.datetimepicker.DPGlobal = DPGlobal;\n\n\t/* DATETIMEPICKER NO CONFLICT\n\t\t* =================== */\n\n\t$.fn.datetimepicker.noConflict = function() {\n\t\t$.fn.datetimepicker = old;\n\t\treturn this;\n\t};\n\n\t/* DATETIMEPICKER DATA-API\n\t\t* ================== */\n\n\t$(document).on('focus.datetimepicker.data-api click.datetimepicker.data-api', '[data-provide=\"datetimepicker\"]',\n\tfunction(e) {\n\t\tvar $this = $(this);\n\t\tif ($this.data('datetimepicker')) return;\n\t\te.preventDefault();\n\t\t// component click requires us to explicitly show it\n\t\t$this.datetimepicker('show');\n\t});\n\t$(function() {\n\t\t$('[data-provide=\"datetimepicker-inline\"]').datetimepicker();\n\t});\n}));\n\n/* ============================================================\n * Bootstrap.Switch v1.3 by Larentis Mattia @spiritualGuru\n * http://www.larentis.eu/switch/\n * ============================================================\n * Licensed under the Apache License, Version 2.0\n * http://www.apache.org/licenses/LICENSE-2.0\n * ============================================================ */\n!function($) {\n\t\"use strict\";\n\t$.fn['bootstrapSwitch'] = function(method) {\n\t\tvar methods = {\n\t\t\tinit: function() {\n\t\t\t\treturn this.each(function() {\n\t\t\t\t\tvar $element = $(this),\n\t\t\t\t\t$div,\n\t\t\t\t\t$switchLeft,\n\t\t\t\t\t$switchRight,\n\t\t\t\t\t$label,\n\t\t\t\t\tmyClasses = \"\",\n\t\t\t\t\tclasses = $element.attr('class'),\n\t\t\t\t\tcolor,\n\t\t\t\t\tmoving,\n\t\t\t\t\tonLabel = \"ON\",\n\t\t\t\t\toffLabel = \"OFF\",\n\t\t\t\t\ticon = false;\n\n\t\t\t\t\t$.each(['size-MINI', 'size-S', 'size-L'],\n\t\t\t\t\tfunction(i, el) {\n\t\t\t\t\t\tif (classes.indexOf(el) >= 0) myClasses = el;\n\t\t\t\t\t});\n\t\t\t\t\t$element.addClass('has-switch');\n\t\t\t\t\tif ($element.data('on') !== undefined) color = \"switch-\" + $element.data('on');\n\t\t\t\t\tif ($element.data('on-label') !== undefined) onLabel = $element.data('on-label');\n\t\t\t\t\tif ($element.data('off-label') !== undefined) offLabel = $element.data('off-label');\n\t\t\t\t\tif ($element.data('icon') !== undefined) icon = $element.data('icon');\n\t\t\t\t\t$switchLeft = $('<span>').addClass(\"switch-left\").addClass(myClasses).addClass(color).html(onLabel);\n\t\t\t\t\tcolor = '';\n\t\t\t\t\tif ($element.data('off') !== undefined) color = \"switch-\" + $element.data('off');\n\t\t\t\t\t$switchRight = $('<span>').addClass(\"switch-right\").addClass(myClasses).addClass(color).html(offLabel);\n\t\t\t\t\t$label = $('<label>').html(\"&nbsp;\").addClass(myClasses).attr('for', $element.find('input').attr('id'));\n\t\t\t\t\tif (icon) {\n\t\t\t\t\t\t$label.html('<i class=\"icon icon-' + icon + '\"></i>');\n\t\t\t\t\t}\n\n\t\t\t\t\t$div = $element.find(':checkbox').wrap($('<div>')).parent().data('animated', false);\n\t\t\t\t\tif ($element.data('animated') !== false) $div.addClass('switch-animate').data('animated', true);\n\t\t\t\t\t$div.append($switchLeft).append($label).append($switchRight);\n\t\t\t\t\t$element.find('>div').addClass($element.find('input').is(':checked') ? 'switch-on': 'switch-off');\n\t\t\t\t\tif ($element.find('input').is(':disabled')) $(this).addClass('deactivate');\n\t\t\t\t\tvar changeStatus = function($this) {\n\t\t\t\t\t\t$this.siblings('label').trigger('mousedown').trigger('mouseup').trigger('click');\n\t\t\t\t\t};\n\t\t\t\t\t$element.on('keydown',\n\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\tif (e.keyCode === 32) {\n\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\tchangeStatus($(e.target).find('span:first'));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\t$switchLeft.on('click',\n\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\tchangeStatus($(this));\n\t\t\t\t\t});\n\n\t\t\t\t\t$switchRight.on('click',\n\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\tchangeStatus($(this));\n\t\t\t\t\t});\n\t\t\t\t\t$element.find('input').on('change',\n\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\tvar $this = $(this),\n\t\t\t\t\t\t$element = $this.parent(),\n\t\t\t\t\t\tthisState = $this.is(':checked'),\n\t\t\t\t\t\tstate = $element.is('.switch-off');\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t$element.css('left', '');\n\t\t\t\t\t\tif (state === thisState) {\n\t\t\t\t\t\t\tif (thisState) $element.removeClass('switch-off').addClass('switch-on');\n\t\t\t\t\t\t\telse $element.removeClass('switch-on').addClass('switch-off');\n\t\t\t\t\t\t\tif ($element.data('animated') !== false) $element.addClass(\"switch-animate\");\n\t\t\t\t\t\t\t$element.parent().trigger('switch-change', {\n\t\t\t\t\t\t\t\t'el': $this,\n\t\t\t\t\t\t\t\t'value': thisState\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$element.find('label').on('mousedown touchstart',\n\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\tvar $this = $(this);\n\t\t\t\t\t\tmoving = false;\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t$this.closest('div').removeClass('switch-animate');\n\t\t\t\t\t\tif ($this.closest('.has-switch').is('.deactivate')) $this.unbind('click');\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t$this.on('mousemove touchmove',\n\t\t\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\t\t\tvar $element = $(this).closest('.switch'),\n\t\t\t\t\t\t\t\trelativeX = (e.pageX || e.originalEvent.targetTouches[0].pageX) - $element.offset().left,\n\t\t\t\t\t\t\t\tpercent = (relativeX / $element.width()) * 100,\n\t\t\t\t\t\t\t\tleft = 25,\n\t\t\t\t\t\t\t\tright = 75;\n\t\t\t\t\t\t\t\tmoving = true;\n\t\t\t\t\t\t\t\tif (percent < left) percent = left;\n\t\t\t\t\t\t\t\telse if (percent > right) percent = right;\n\t\t\t\t\t\t\t\t$element.find('>div').css('left', (percent - right) + \"%\")\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t$this.on('click touchend',\n\t\t\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\t\t\tvar $this = $(this),\n\t\t\t\t\t\t\t\t$target = $(e.target),\n\t\t\t\t\t\t\t\t$myCheckBox = $target.siblings('input');\n\t\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t$this.unbind('mouseleave');\n\t\t\t\t\t\t\t\tif (moving) $myCheckBox.prop('checked', !(parseInt($this.parent().css('left')) < -25));\n\t\t\t\t\t\t\t\telse $myCheckBox.prop(\"checked\", !$myCheckBox.is(\":checked\"));\n\t\t\t\t\t\t\t\tmoving = false;\n\t\t\t\t\t\t\t\t$myCheckBox.trigger('change');\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t$this.on('mouseleave',\n\t\t\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\t\t\tvar $this = $(this),\n\t\t\t\t\t\t\t\t$myCheckBox = $this.siblings('input');\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$this.unbind('mouseleave');\n\t\t\t\t\t\t\t\t$this.trigger('mouseup');\n\t\t\t\t\t\t\t\t$myCheckBox.prop('checked', !(parseInt($this.parent().css('left')) < -25)).trigger('change');\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t$this.on('mouseup',\n\t\t\t\t\t\t\tfunction(e) {\n\t\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t$(this).unbind('mousemove');\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\ttoggleActivation: function() {\n\t\t\t\t$(this).toggleClass('deactivate');\n\t\t\t},\n\t\t\tisActive: function() {\n\t\t\t\treturn ! $(this).hasClass('deactivate');\n\t\t\t},\n\t\t\tsetActive: function(active) {\n\t\t\t\tif (active) $(this).removeClass('deactivate');\n\t\t\t\telse $(this).addClass('deactivate');\n\t\t\t},\n\t\t\ttoggleState: function(skipOnChange) {\n\t\t\t\tvar $input = $(this).find('input:checkbox');\n\t\t\t\t$input.prop('checked', !$input.is(':checked')).trigger('change', skipOnChange);\n\t\t\t},\n\t\t\tsetState: function(value, skipOnChange) {\n\t\t\t\t$(this).find('input:checkbox').prop('checked', value).trigger('change', skipOnChange);\n\t\t\t},\n\t\t\tstatus: function() {\n\t\t\t\treturn $(this).find('input:checkbox').is(':checked');\n\t\t\t},\n\t\t\tdestroy: function() {\n\t\t\t\tvar $div = $(this).find('div'),\n\t\t\t\t$checkbox;\n\t\t\t\t$div.find(':not(input:checkbox)').remove();\n\t\t\t\t$checkbox = $div.children();\n\t\t\t\t$checkbox.unwrap().unwrap();\n\t\t\t\t$checkbox.unbind('change');\n\t\t\t\treturn $checkbox;\n\t\t\t}\n\t\t};\n\n\t\tif (methods[method]) return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n\t\telse if (typeof method === 'object' || !method) return methods.init.apply(this, arguments);\n\t\telse $.error('Method ' + method + ' does not exist!');\n\t};\n} (jQuery);\n\n$(function() {\n\t$('.switch')['bootstrapSwitch']();\n});"
  },
  {
    "path": "public/static/h-ui.admin/css/H-ui.admin.css",
    "content": "@charset \"utf-8\";\n/* -----------H-ui前端框架-------------\n* H-ui.admin.css v2.5\n* http://www.h-ui.net/\n* Created & Modified by guojunhui\n* Date modified 2016.05.31\n*\n* Copyright 2013-2016 北京颖杰联创科技有限公司 All rights reserved.\n* Licensed under MIT license.\n* http://opensource.org/licenses/MIT\n*\n*/\nhtml{height:100%}\nbody{min-height: 100%;position: relative;font-size:14px;color:#333; background-color:#fff}\na{color:#333}a:hover,a:focus,.maincolor,.maincolor a{color:#06c}\n.bg-1{ background-color:#f5fafe}\nh4{line-height:30px}\n\n/*页面框架*/\n.Hui-header{position:absolute;top:0; right:0; left:0;height:44px;z-index:999; padding:0 15px}\n.Hui-aside{position: absolute;top:44px;bottom:0;left:0;padding-top:10px;width:199px;z-index:99;overflow:auto; background-color:rgba(238,238,238,0.98);_background-color:rgb(238,238,238);border-right: 1px solid #e5e5e5}\n.Hui-article-box{position: absolute;top:44px;right:0;bottom: 0;left:199px; overflow:hidden; z-index:1; background-color:#fff}\n\t.Hui-article{position: absolute;top:34px;bottom:0;left:0; right:0;overflow:auto;z-index:1}\n.Hui-container{ padding:45px 0 0}\n.Hui-aside,.Hui-article-box,.dislpayArrow{-moz-transition: all 0.2s ease 0s;-webkit-transition: all 0.2s ease 0s;-ms-transition: all 0.2s ease 0s;-o-transition: all 0.2s ease 0s;transition: all 0.2s ease 0s}\n.big-page .Hui-article-box,.big-page .dislpayArrow,.big-page .breadcrumb{left:0px}\n.big-page .Hui-aside{ left:-200px}\n.page-container{ padding:20px}\n@media (max-width: 767px) {\n\t.page-container{ padding:15px}\n}\n/*组件*/\n/*logo*/\n\n/*导航*/\n#Hui-nav > ul > li{ font-weight:normal}\n@media (max-width: 767px) {\n\t#Hui-nav{display: block; top: 0; left: 65px; right: 65px}\n\t#Hui-nav > ul { width: 100%}\n\t#Hui-nav > ul > li{ width: 24%;text-align:center;}\n\t#Hui-nav > ul > li a{ text-align: center; padding: 0}\n}\n#Hui-userbar{right:20px; position:absolute; top:0;}\n#Hui-userbar > ul > li > a{padding:0 10px}\n\t\n#Hui-msg .badge{ position:absolute; left:19px; top:4px; font-size:12px; font-weight:normal; padding:1px 5px}\n/*左侧菜单*/\n.Hui-aside .menu_dropdown dl{ margin-bottom:0}\n.Hui-aside .menu_dropdown dt{display:block;line-height:35px;padding-left:15px;cursor:pointer;position:relative;border-bottom: 1px solid #e5e5e5;font-weight:normal}\n.Hui-aside .menu_dropdown dt .menu_dropdown-arrow{ position:absolute;overflow: hidden; top:0; right:15px;transition-duration:0.3s ;transition-property:all}\n.Hui-aside .menu_dropdown dd{ display:none}\n.Hui-aside .menu_dropdown dt.selected .menu_dropdown-arrow{transform: rotate(180deg)}\n.Hui-aside .menu_dropdown dd.selected{display:block; margin-left:0px}\n.Hui-aside .menu_dropdown ul{padding:0px}\n.Hui-aside .menu_dropdown li{line-height:35px;overflow:hidden;zoom:1}\n.Hui-aside .menu_dropdown li a{padding-left:15px; display:block;font-weight: bold; margin:0}\n.Hui-aside .menu_dropdown li a i{ font-weight: normal}\n.Hui-aside .menu_dropdown dd ul{padding:3px 8px}\n.Hui-aside .menu_dropdown dd li{line-height:32px}\n.Hui-aside .menu_dropdown dd li a{line-height:32px;padding-left:26px; border-bottom:none; font-weight:normal}\n.Hui-aside .menu_dropdown li a:hover{text-decoration:none}\n.Hui-aside .menu_dropdown li.current a,.menu_dropdown li.current a:hover{background-color:rgba(255,255,255,0.2)}\n/*菜单收缩切换*/\n.dislpayArrow{position: absolute;top: 0;bottom: 0;left:200px;width:0px; height:100%;z-index:10}\n.dislpayArrow a{ position:absolute; display:block; width:17px; height:61px;top:50%; margin-top:-30px;outline:none}\n.dislpayArrow a.open{ background-position:0 -61px}\n.dislpayArrow a:hover{ text-decoration:none; background-position:right 0}\n.dislpayArrow a.open:hover{background-position:right -61px}\n\n/*选项卡导航*/\n.Hui-tabNav-wp{position:relative; height:35px;overflow:hidden}\n.Hui-tabNav,\n.Hui-tabNav .acrossTab li\n,.Hui-tabNav .acrossTab li em{background-image:url(../images/acrossTab/acrossTab-2.png)}\n.Hui-tabNav{height:35px; padding-right:75px;overflow:hidden; position:relative;background-color:#efeef0; background-repeat: repeat-x; background-position: 0 -175px;}\n.Hui-tabNav .acrossTab{ position:absolute; height:26px; line-height:26px; background:none; top:8px; left:0;padding-top:0}\n.Hui-tabNav .acrossTab li{height:26px;line-height:26px;}\n.Hui-tabNav .acrossTab li em{ right:-16px; height: 26px; width: 16px}\n.loading {background:url(../images/loading.gif) no-repeat center; height:100px}\n.show_iframe{ position:absolute; top:0; right:0; left:0; bottom:0;}\n.show_iframe iframe {position: absolute;bottom: 0;height: 100%;width: 100%}\n.Hui-tabNav-more {position: absolute;right:0px;width:70px;top:4px;display: none}\n\n/*面包屑导航*/\n.breadcrumb{background-color:#f5f5f5; padding:0 20px; position:relative; z-index:99}\n@media (max-width: 767px) {\n\t.breadcrumb{ padding:0 15px;}\n\t.show_iframe{-webkit-overflow-scrolling: touch;overflow-y: scroll;}\n}\n\n/*横向手机 竖向平板*/\n@media (max-width: 767px) {\n\t.Hui-aside{ display:none;float:none; width:100%; height:auto; margin-top:0;padding-top:0;bottom:auto}\n\t.big-page .Hui-aside{ left:0!important}\n\t\t.menu_dropdown dt{line-height:44px}\n\t\t.menu_dropdown li,.menu_dropdown dd li,.menu_dropdown dd li a{ line-height:44px}\n  .Hui-tabNav{ position:fixed; z-index:998}\n  .Hui-article{ top:44px}\n  .Hui-article-box{ position:static; left:0}\n  .Hui-article-box .pd-20{padding:15px}\n\t\t.Hui-article{left:0}\n\t\t.Hui-container .bk-gray{ border:none}\n\t\t.Hui-container .pd-10{ padding:0}\n}\n\n/*==============以下是业务相关的样式====================*/\n/*权限*/\n.permission-list{ border:solid 1px #eee;}\n.permission-list > dt{ background-color:#efefef;padding:5px 10px}\n.permission-list > dd{ padding:10px; padding-left:30px}\n.permission-list > dd > dl{ border-bottom:solid 1px #eee; padding:5px 0}\n.permission-list > dd > dl > dt{ display:inline-block;float:left;white-space:nowrap;width:100px}\n.permission-list > dd > dl > dd{ margin-left:100px;}\n.permission-list > dd > dl > dd > label{ padding-right:10px}\n\n/*图片预览*/\n.portfolio-area{ margin-right: -20px;}\n.portfolio-area li{position: relative; float: left; margin-right: 20px; width:162px; height:162px;margin-top: 20px;}\n.portfolio-area li.hover{ z-index:9}\n.portfolio-area li .portfoliobox{ position: absolute; top: 0; left: 0; width: 152px; height: 152px;padding:5px;border: solid 1px #eee; background-color: #fff;}\n.portfolio-area li .checkbox{position: absolute; top: 10px; right: 5px; cursor:pointer}\n.portfolio-area li.hover .portfoliobox{ height:auto;padding-bottom:10px;box-shadow:0 1px 3px rgba(68, 68, 68,0.3);-moz-box-shadow:0 1px 3px rgba(68, 68, 68,0.3);-webkit-box-shadow:0 1px 3px rgba(68, 68, 68,0.3)}\n.portfolio-area li .picbox{width: 150px; height: 150px;overflow: hidden;text-align: center;vertical-align:middle;display:table-cell; line-height:150px;}\n.portfolio-area li .picbox img{max-width:150px; max-height:150px;vertical-align:middle;}\n.portfolio-area li .textbox{ display: none; margin-top: 5px;}\n.portfolio-area li.hover .textbox{ display: block;}\n.portfolio-area li label{ display:block; cursor:pointer}"
  },
  {
    "path": "public/static/h-ui.admin/css/H-ui.login.css",
    "content": "@charset \"utf-8\";\n/* -----------H-ui前端框架-------------\n* H-ui.login.css v2.2.1\t后台登录页样式\n* http://www.h-ui.net/\n* Created & Modified by guojunhui\n* Date modified 2015.6.5\n*\n* Copyright 2013-2017 北京颖杰联创科技有限公司 All rights reserved.\n* Licensed under MIT license.\n* http://opensource.org/licenses/MIT\n*\n*/\nhtml, body{ height:100%}\nbody{font-size:14px}\n\n.header,.footer{ position:absolute; left:0; right:0; width:100%; z-index:99}\n.header{top:0; height:60px; background:#426374 url(../images/logo.png) no-repeat 0 center}\n\n.loginWraper{ position:absolute;width:100%; left:0; top:0; bottom:0; right:0; z-index:1; background:#3283AC url(../images/admin-login-bg.jpg) no-repeat center}\n.loginBox{ position:absolute; width:617px; height:330px; background:url(../images/admin-loginform-bg.png) no-repeat; left:50%; top:50%; margin-left:-309px; margin-top:-184px; padding-top:38px}\n@media (max-width:617px) {\n\t.loginbox{ width:100%; position:static; margin-top:0; margin-left:0;}\n}\n.loginBox .row{margin-top:20px;}\n.loginBox .row .form-label .Hui-iconfont{ font-size:24px}\n.loginBox .input-text{ width:360px}\n@media (max-width:617px) {\n\t.loginBox .input-text{ width:80%}\n}\n\t.yzm a{ color:#426374; font-size:12px}\n\n#span_msg{ font-size:14px; color:Red; line-height:40px; height:40px; margin-left:10px; width:160px;; float:left}\n\n.hd_msg{font-size:12px; color:#fff; height:30px; z-index:100;position: absolute; padding-left:50px; padding-top:5px}\n.hd_msg a{ color:#fff}\n.hd_msg a:hover{ color:#fff; text-decoration:underline}\n\n.footer{ height:46px; line-height:46px; bottom:0; text-align:center; color:#fff; font-size:12px; background-color:#426374}\n\n#ie6-warning{background:#fff url(/jscss/demoimg/201006/warning.gif) no-repeat 3px center;position:absolute;top:0;left:0;font-size:12px;color:#333;width:97%;padding: 2px 15px 2px 23px;text-align:left}\n#ie6-warning a {text-decoration:none}"
  },
  {
    "path": "public/static/h-ui.admin/css/style.css",
    "content": "@charset \"utf-8\";\n/* 你自己的样式 */\n\n"
  },
  {
    "path": "public/static/h-ui.admin/js/H-ui.admin.js",
    "content": "/* -----------H-ui前端框架-------------\n* H-ui.admin.js v3.1\n* http://www.h-ui.net/\n* Created & Modified by guojunhui\n* Date modified 2017.02.03\n* Copyright 2013-2017 北京颖杰联创科技有限公司 All rights reserved.\n* Licensed under MIT license.\n* http://opensource.org/licenses/MIT\n*/\nvar num=0,oUl=$(\"#min_title_list\"),hide_nav=$(\"#Hui-tabNav\");\n\n/*获取顶部选项卡总长度*/\nfunction tabNavallwidth(){\n\tvar taballwidth=0,\n\t\t$tabNav = hide_nav.find(\".acrossTab\"),\n\t\t$tabNavWp = hide_nav.find(\".Hui-tabNav-wp\"),\n\t\t$tabNavitem = hide_nav.find(\".acrossTab li\"),\n\t\t$tabNavmore =hide_nav.find(\".Hui-tabNav-more\");\n\tif (!$tabNav[0]){return}\n\t$tabNavitem.each(function(index, element) {\n        taballwidth += Number(parseFloat($(this).width()+60))\n    });\n\t$tabNav.width(taballwidth+25);\n\tvar w = $tabNavWp.width();\n\tif(taballwidth+25>w){\n\t\t$tabNavmore.show()}\n\telse{\n\t\t$tabNavmore.hide();\n\t\t$tabNav.css({left:0});\n\t}\n}\n\n/*左侧菜单响应式*/\nfunction Huiasidedisplay(){\n\tif($(window).width()>=768){\n\t\t$(\".Hui-aside\").show();\n\t} \n}\n/*获取皮肤cookie*/\nfunction getskincookie(){\n\tvar v = $.cookie(\"Huiskin\");\n\tvar hrefStr=$(\"#skin\").attr(\"href\");\n\tif(v==null||v==\"\"){\n\t\tv=\"default\";\n\t}\n\tif(hrefStr!=undefined){\n\t\tvar hrefRes=hrefStr.substring(0,hrefStr.lastIndexOf('skin/'))+'skin/'+v+'/skin.css';\n\t\t$(\"#skin\").attr(\"href\",hrefRes);\n\t}\n}\n/*菜单导航*/\nfunction Hui_admin_tab(obj){\n\tvar bStop = false,\n\t\tbStopIndex = 0,\n\t\thref = $(obj).attr('data-href'),\n\t\ttitle = $(obj).attr(\"data-title\"),\n\t\ttopWindow = $(window.parent.document),\n\t\tshow_navLi = topWindow.find(\"#min_title_list li\"),\n\t\tiframe_box = topWindow.find(\"#iframe_box\");\n\t//console.log(topWindow);\n\tif(!href||href==\"\"){\n\t\talert(\"data-href不存在，v2.5版本之前用_href属性，升级后请改为data-href属性\");\n\t\treturn false;\n\t}if(!title){\n\t\talert(\"v2.5版本之后使用data-title属性\");\n\t\treturn false;\n\t}\n\tif(title==\"\"){\n\t\talert(\"data-title属性不能为空\");\n\t\treturn false;\n\t}\n\tshow_navLi.each(function() {\n\t\tif($(this).find('span').attr(\"data-href\")==href){\n\t\t\tbStop=true;\n\t\t\tbStopIndex=show_navLi.index($(this));\n\t\t\treturn false;\n\t\t}\n\t});\n\tif(!bStop){\n\t\tcreatIframe(href,title);\n\t\tmin_titleList();\n\t}\n\telse{\n\t\tshow_navLi.removeClass(\"active\").eq(bStopIndex).addClass(\"active\");\t\t\t\n\t\tiframe_box.find(\".show_iframe\").hide().eq(bStopIndex).show().find(\"iframe\").attr(\"src\",href);\n\t}\t\n}\n\n/*最新tab标题栏列表*/\nfunction min_titleList(){\n\tvar topWindow = $(window.parent.document),\n\t\tshow_nav = topWindow.find(\"#min_title_list\"),\n\t\taLi = show_nav.find(\"li\");\n}\n\n/*创建iframe*/\nfunction creatIframe(href,titleName){\n\tvar topWindow=$(window.parent.document),\n\t\tshow_nav=topWindow.find('#min_title_list'),\n\t\tiframe_box=topWindow.find('#iframe_box'),\n\t\tiframeBox=iframe_box.find('.show_iframe'),\n\t\t$tabNav = topWindow.find(\".acrossTab\"),\n\t\t$tabNavWp = topWindow.find(\".Hui-tabNav-wp\"),\n\t\t$tabNavmore =topWindow.find(\".Hui-tabNav-more\");\n\tvar taballwidth=0;\n\t\t\n\tshow_nav.find('li').removeClass(\"active\");\t\n\tshow_nav.append('<li class=\"active\"><span data-href=\"'+href+'\">'+titleName+'</span><i></i><em></em></li>');\n\tif('function'==typeof $('#min_title_list li').contextMenu){\n\t\t$(\"#min_title_list li\").contextMenu('Huiadminmenu', {\n\t\t\tbindings: {\n\t\t\t\t'closethis': function(t) {\n\t\t\t\t\tvar $t = $(t);\t\t\t\t\n\t\t\t\t\tif($t.find(\"i\")){\n\t\t\t\t\t\t$t.find(\"i\").trigger(\"click\");\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t'closeall': function(t) {\n\t\t\t\t\t$(\"#min_title_list li i\").trigger(\"click\");\n\t\t\t\t},\n\t\t\t}\n\t\t});\n\t}else {\n\t\t\n\t}\t\n\tvar $tabNavitem = topWindow.find(\".acrossTab li\");\n\tif (!$tabNav[0]){return}\n\t$tabNavitem.each(function(index, element) {\n        taballwidth+=Number(parseFloat($(this).width()+60))\n    });\n\t$tabNav.width(taballwidth+25);\n\tvar w = $tabNavWp.width();\n\tif(taballwidth+25>w){\n\t\t$tabNavmore.show()}\n\telse{\n\t\t$tabNavmore.hide();\n\t\t$tabNav.css({left:0})\n\t}\t\n\tiframeBox.hide();\n\tiframe_box.append('<div class=\"show_iframe\"><div class=\"loading\"></div><iframe frameborder=\"0\" src='+href+'></iframe></div>');\n\tvar showBox=iframe_box.find('.show_iframe:visible');\n\tshowBox.find('iframe').load(function(){\n\t\tshowBox.find('.loading').hide();\n\t});\n}\n\n\n\n/*关闭iframe*/\nfunction removeIframe(){\n\tvar topWindow = $(window.parent.document),\n\t\tiframe = topWindow.find('#iframe_box .show_iframe'),\n\t\ttab = topWindow.find(\".acrossTab li\"),\n\t\tshowTab = topWindow.find(\".acrossTab li.active\"),\n\t\tshowBox=topWindow.find('.show_iframe:visible'),\n\t\ti = showTab.index();\n\ttab.eq(i-1).addClass(\"active\");\n\ttab.eq(i).remove();\n\tiframe.eq(i-1).show();\t\n\tiframe.eq(i).remove();\n}\n\n/*关闭所有iframe*/\nfunction removeIframeAll(){\n\tvar topWindow = $(window.parent.document),\n\t\tiframe = topWindow.find('#iframe_box .show_iframe'),\n\t\ttab = topWindow.find(\".acrossTab li\");\n\tfor(var i=0;i<tab.length;i++){\n\t\tif(tab.eq(i).find(\"i\").length>0){\n\t\t\ttab.eq(i).remove();\n\t\t\tiframe.eq(i).remove();\n\t\t}\n\t}\n}\n\n/*弹出层*/\n/*\n\t参数解释：\n\ttitle\t标题\n\turl\t\t请求的url\n\tid\t\t需要操作的数据id\n\tw\t\t弹出层宽度（缺省调默认值）\n\th\t\t弹出层高度（缺省调默认值）\n*/\nfunction layer_show(title,url,w,h){\n\tif (title == null || title == '') {\n\t\ttitle=false;\n\t};\n\tif (url == null || url == '') {\n\t\turl=\"404.html\";\n\t};\n\tif (w == null || w == '') {\n\t\tw=800;\n\t};\n\tif (h == null || h == '') {\n\t\th=($(window).height() - 50);\n\t};\n\tlayer.open({\n\t\ttype: 2,\n\t\tarea: [w+'px', h +'px'],\n\t\tfix: false, //不固定\n\t\tmaxmin: true,\n\t\tshade:0.4,\n\t\ttitle: title,\n\t\tcontent: url\n\t});\n}\n/*关闭弹出框口*/\nfunction layer_close(){\n\tvar index = parent.layer.getFrameIndex(window.name);\n\tparent.layer.close(index);\n}\n\n/*时间*/\nfunction getHTMLDate(obj) {\n    var d = new Date();\n    var weekday = new Array(7);\n    var _mm = \"\";\n    var _dd = \"\";\n    var _ww = \"\";\n    weekday[0] = \"星期日\";\n    weekday[1] = \"星期一\";\n    weekday[2] = \"星期二\";\n    weekday[3] = \"星期三\";\n    weekday[4] = \"星期四\";\n    weekday[5] = \"星期五\";\n    weekday[6] = \"星期六\";\n    _yy = d.getFullYear();\n    _mm = d.getMonth() + 1;\n    _dd = d.getDate();\n    _ww = weekday[d.getDay()];\n    obj.html(_yy + \"年\" + _mm + \"月\" + _dd + \"日 \" + _ww);\n};\n\n$(function(){\n\tgetHTMLDate($(\"#top_time\"));\n\tgetskincookie();\n\t//layer.config({extend: 'extend/layer.ext.js'});\n\tHuiasidedisplay();\n\tvar resizeID;\n\t$(window).resize(function(){\n\t\tclearTimeout(resizeID);\n\t\tresizeID = setTimeout(function(){\n\t\t\tHuiasidedisplay();\n\t\t},500);\n\t});\n\t\n\t$(\".nav-toggle\").click(function(){\n\t\t$(\".Hui-aside\").slideToggle();\n\t});\n\t$(\".Hui-aside\").on(\"click\",\".menu_dropdown dd li a\",function(){\n\t\tif($(window).width()<768){\n\t\t\t$(\".Hui-aside\").slideToggle();\n\t\t}\n\t});\n\t/*左侧菜单*/\n\t$(\".Hui-aside\").Huifold({\n\t\ttitCell:'.menu_dropdown dl dt',\n\t\tmainCell:'.menu_dropdown dl dd',\n\t});\n\t\n\t/*选项卡导航*/\n\t$(\".Hui-aside\").on(\"click\",\".menu_dropdown a\",function(){\n\t\tHui_admin_tab(this);\n\t});\n\t\n\t$(document).on(\"click\",\"#min_title_list li\",function(){\n\t\tvar bStopIndex=$(this).index();\n\t\tvar iframe_box=$(\"#iframe_box\");\n\t\t$(\"#min_title_list li\").removeClass(\"active\").eq(bStopIndex).addClass(\"active\");\n\t\tiframe_box.find(\".show_iframe\").hide().eq(bStopIndex).show();\n\t});\n\t$(document).on(\"click\",\"#min_title_list li i\",function(){\n\t\tvar aCloseIndex=$(this).parents(\"li\").index();\n\t\t$(this).parent().remove();\n\t\t$('#iframe_box').find('.show_iframe').eq(aCloseIndex).remove();\t\n\t\tnum==0?num=0:num--;\n\t\ttabNavallwidth();\n\t});\n\t$(document).on(\"dblclick\",\"#min_title_list li\",function(){\n\t\tvar aCloseIndex=$(this).index();\n\t\tvar iframe_box=$(\"#iframe_box\");\n\t\tif(aCloseIndex>0){\n\t\t\t$(this).remove();\n\t\t\t$('#iframe_box').find('.show_iframe').eq(aCloseIndex).remove();\t\n\t\t\tnum==0?num=0:num--;\n\t\t\t$(\"#min_title_list li\").removeClass(\"active\").eq(aCloseIndex-1).addClass(\"active\");\n\t\t\tiframe_box.find(\".show_iframe\").hide().eq(aCloseIndex-1).show();\n\t\t\ttabNavallwidth();\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\t});\n\ttabNavallwidth();\n\t\n\t$('#js-tabNav-next').click(function(){\n\t\tnum==oUl.find('li').length-1?num=oUl.find('li').length-1:num++;\n\t\ttoNavPos();\n\t});\n\t$('#js-tabNav-prev').click(function(){\n\t\tnum==0?num=0:num--;\n\t\ttoNavPos();\n\t});\n\t\n\tfunction toNavPos(){\n\t\toUl.stop().animate({'left':-num*100},100);\n\t}\n\t\n\t/*换肤*/\n\t$(\"#Hui-skin .dropDown-menu a\").click(function(){\n\t\tvar v = $(this).attr(\"data-val\");\n\t\t$.cookie(\"Huiskin\", v);\n\t\tvar hrefStr=$(\"#skin\").attr(\"href\");\n\t\tvar hrefRes=hrefStr.substring(0,hrefStr.lastIndexOf('skin/'))+'skin/'+v+'/skin.css';\n\t\t$(window.frames.document).contents().find(\"#skin\").attr(\"href\",hrefRes);\n\t});\n}); \n"
  },
  {
    "path": "public/static/h-ui.admin/js/de_DE.txt",
    "content": "{\n\t\"processing\": \"处理中...\",\n\t\"lengthMenu\": \"每页显示 _MENU_ 条\",\n\t\"zeroRecords\": \"没有找到匹配的记录\",\n\t\"sProcessing\": \"&lt;img src=’./loading.gif’ /&gt;\",\n\t\"info\": \"显示 _START_ 到 _END_ ，共 _TOTAL_ 条\",\n\t\"infoEmpty\": \"0条\",\n\t\"infoFiltered\": \"(从 _MAX_ 条中过滤)\",\n\t\"infoPostFix\": \"\",\n\t\"search\": \"当前检索\",\n\t\"url\": \"\",\n\t\"paginate\": {\n\t\t\"first\":    \"第一页\",\n\t\t\"previous\": \"上一页\",\n\t\t\"next\":     \"下一页\",\n\t\t\"last\":     \"最后一页\"\n\t}\n}"
  },
  {
    "path": "public/static/h-ui.admin/skin/blue/skin.css",
    "content": "@charset \"utf-8\";\n/* 蓝色 */\n/*全站默认字体颜色*/\na{color:#333}a:hover,a:focus,.maincolor,.maincolor a{color:#06c}\n.navbar{ background:#2d6dcc}/*顶部导航*/\n\t.navbar-logo,.navbar-logo-m,.navbar-slogan,.navbar-userbar{color:#fff}/*logo 及 用户信息文字颜色*/\n\t.navbar-logo:hover,.navbar-logo-m:hover{color:#fff;text-decoration: none}\n\t\n.navbar-nav > ul > li, .navbar-nav > ul > li > a{ color:#fff}/*顶部导航文字颜色*/\n.navbar-userbar > ul> > li,.navbar-userbar > ul> > li > a{ color:#fff}\n\n.Hui-aside{}/*侧边栏*/\n\t.Hui-aside .menu_dropdown dt{color:#333}/*左侧二级导航菜单*/\n\t.Hui-aside .menu_dropdown dt:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt:hover [class^=\"icon-\"]{ color:#7e8795}\n\t.Hui-aside .menu_dropdown li a{color:#666;border-bottom: 1px solid #e5e5e5}\n\t.Hui-aside .menu_dropdown li a:hover{color:#148cf1;background-color:#fafafa}\n\t.Hui-aside .menu_dropdown li.current a,.menu_dropdown li.current a:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt .Hui-iconfont{ color:#a0a7b1}\n\t.Hui-aside .menu_dropdown dt .menu_dropdown-arrow{ color:#b6b7b8}\t\n\t.dislpayArrow a{background:url(icon_arrow.png) no-repeat 0 0}\n.tabBar {border-bottom: 2px solid #2d6dcc}\n.tabBar span.current{background-color:#2d6dcc}"
  },
  {
    "path": "public/static/h-ui.admin/skin/default/skin.css",
    "content": "@charset \"utf-8\";\n/* 默认 黑色 */\t\n/*全站默认字体颜色*/\na{color:#333}a:hover,a:focus,.maincolor,.maincolor a{color:#06c}\n.navbar{ background:#222}/*顶部导航*/\n\t.navbar-logo,.navbar-logo-m,.navbar-slogan,.navbar-userbar{color:#fff}/*logo 及 用户信息文字颜色*/\n\t.navbar-logo:hover,.navbar-logo-m:hover{color:#fff;text-decoration: none}\n\t\n.navbar-nav > ul > li, .navbar-nav > ul > li > a{ color:#fff}/*顶部导航文字颜色*/\n.navbar-userbar > ul> > li,.navbar-userbar > ul> > li > a{ color:#fff}\n\n.Hui-aside{}/*侧边栏*/\n\t.Hui-aside .menu_dropdown dt{color:#333}/*左侧二级导航菜单*/\n\t.Hui-aside .menu_dropdown dt:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt:hover [class^=\"icon-\"]{ color:#7e8795}\n\t.Hui-aside .menu_dropdown li a{color:#666;border-bottom: 1px solid #e5e5e5}\n\t.Hui-aside .menu_dropdown li a:hover{color:#148cf1;background-color:#fafafa}\n\t.Hui-aside .menu_dropdown li.current a,.menu_dropdown li.current a:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt .Hui-iconfont{ color:#a0a7b1}\n\t.Hui-aside .menu_dropdown dt .menu_dropdown-arrow{ color:#b6b7b8}\t\n\t.dislpayArrow a{background:url(icon_arrow.png) no-repeat 0 0}"
  },
  {
    "path": "public/static/h-ui.admin/skin/green/skin.css",
    "content": "@charset \"utf-8\";\n/* 绿色 */\n/*全站默认字体颜色*/\na{color:#333}a:hover,a:focus,.maincolor,.maincolor a{color:#06c}\n.navbar{ background:#19a97b}/*顶部导航*/\n\t.navbar-logo,.navbar-logo-m,.navbar-slogan,.navbar-userbar{color:#fff}/*logo 及 用户信息文字颜色*/\n\t.navbar-logo:hover,.navbar-logo-m:hover{color:#fff;text-decoration: none}\n\t\n.navbar-nav > ul > li, .navbar-nav > ul > li > a{ color:#fff}/*顶部导航文字颜色*/\n.navbar-userbar > ul> > li,.navbar-userbar > ul> > li > a{ color:#fff}\n\n.Hui-aside{}/*侧边栏*/\n\t.Hui-aside .menu_dropdown dt{color:#333}/*左侧二级导航菜单*/\n\t.Hui-aside .menu_dropdown dt:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt:hover [class^=\"icon-\"]{ color:#7e8795}\n\t.Hui-aside .menu_dropdown li a{color:#666;border-bottom: 1px solid #e5e5e5}\n\t.Hui-aside .menu_dropdown li a:hover{color:#148cf1;background-color:#fafafa}\n\t.Hui-aside .menu_dropdown li.current a,.menu_dropdown li.current a:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt .Hui-iconfont{ color:#a0a7b1}\n\t.Hui-aside .menu_dropdown dt .menu_dropdown-arrow{ color:#b6b7b8}\t\n\t.dislpayArrow a{background:url(icon_arrow.png) no-repeat 0 0}\n.tabBar {border-bottom: 2px solid #19a97b}\n.tabBar span.current{background-color:#19a97b}"
  },
  {
    "path": "public/static/h-ui.admin/skin/orange/skin.css",
    "content": "@charset \"utf-8\";\n/* 橙色 */\n/*全站默认字体颜色*/\na{color:#333}a:hover,a:focus,.maincolor,.maincolor a{color:#06c}\n.navbar{ background:#ff4a00}/*顶部导航*/\n\t.navbar-logo,.navbar-logo-m,.navbar-slogan,.navbar-userbar{color:#fff}/*logo 及 用户信息文字颜色*/\n\t.navbar-logo:hover,.navbar-logo-m:hover{color:#fff;text-decoration: none}\n\t\n.navbar-nav > ul > li, .navbar-nav > ul > li > a{ color:#fff}/*顶部导航文字颜色*/\n.navbar-userbar > ul> > li,.navbar-userbar > ul> > li > a{ color:#fff}\n\n.Hui-aside{}/*侧边栏*/\n\t.Hui-aside .menu_dropdown dt{color:#333}/*左侧二级导航菜单*/\n\t.Hui-aside .menu_dropdown dt:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt:hover [class^=\"icon-\"]{ color:#7e8795}\n\t.Hui-aside .menu_dropdown li a{color:#666;border-bottom: 1px solid #e5e5e5}\n\t.Hui-aside .menu_dropdown li a:hover{color:#148cf1;background-color:#fafafa}\n\t.Hui-aside .menu_dropdown li.current a,.menu_dropdown li.current a:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt .Hui-iconfont{ color:#a0a7b1}\n\t.Hui-aside .menu_dropdown dt .menu_dropdown-arrow{ color:#b6b7b8}\t\n\t.dislpayArrow a{background:url(icon_arrow.png) no-repeat 0 0}\n.tabBar {border-bottom: 2px solid #ff4a00}\n.tabBar span.current{background-color:#ff4a00}"
  },
  {
    "path": "public/static/h-ui.admin/skin/red/skin.css",
    "content": "@charset \"utf-8\";\n/* 红色 */\n/*全站默认字体颜色*/\na{color:#333}a:hover,a:focus,.maincolor,.maincolor a{color:#06c}\n.navbar{ background:#c81623}/*顶部导航*/\n\t.navbar-logo,.navbar-logo-m,.navbar-slogan,.navbar-userbar{color:#fff}/*logo 及 用户信息文字颜色*/\n\t.navbar-logo:hover,.navbar-logo-m:hover{color:#fff;text-decoration: none}\n\t\n.navbar-nav > ul > li, .navbar-nav > ul > li > a{ color:#fff}/*顶部导航文字颜色*/\n.navbar-userbar > ul> > li,.navbar-userbar > ul> > li > a{ color:#fff}\n\n.Hui-aside{}/*侧边栏*/\n\t.Hui-aside .menu_dropdown dt{color:#333}/*左侧二级导航菜单*/\n\t.Hui-aside .menu_dropdown dt:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt:hover [class^=\"icon-\"]{ color:#7e8795}\n\t.Hui-aside .menu_dropdown li a{color:#666;border-bottom: 1px solid #e5e5e5}\n\t.Hui-aside .menu_dropdown li a:hover{color:#148cf1;background-color:#fafafa}\n\t.Hui-aside .menu_dropdown li.current a,.menu_dropdown li.current a:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt .Hui-iconfont{ color:#a0a7b1}\n\t.Hui-aside .menu_dropdown dt .menu_dropdown-arrow{ color:#b6b7b8}\t\n\t.dislpayArrow a{background:url(icon_arrow.png) no-repeat 0 0}\n.tabBar {border-bottom: 2px solid #c81623}\n.tabBar span.current{background-color:#c81623}"
  },
  {
    "path": "public/static/h-ui.admin/skin/yellow/skin.css",
    "content": "@charset \"utf-8\";\n/* 黄色 */\n/*全站默认字体颜色*/\na{color:#333}a:hover,a:focus,.maincolor,.maincolor a{color:#06c}\n.navbar{ background:#ffd200}/*顶部导航*/\n\t.navbar-logo,.navbar-logo-m,.navbar-slogan,.navbar-userbar{color:#282828}/*logo 及 用户信息文字颜色*/\n\t.navbar-logo:hover,.navbar-logo-m:hover{color:#282828;text-decoration: none}\n\t\n.navbar-nav > ul > li, .navbar-nav > ul > li > a{ color:#282828}/*顶部导航文字颜色*/\n.navbar-userbar > ul> > li,.navbar-userbar > ul> > li > a{ color:#282828}\n\n.Hui-aside{}/*侧边栏*/\n\t.Hui-aside .menu_dropdown dt{color:#333}/*左侧二级导航菜单*/\n\t.Hui-aside .menu_dropdown dt:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt:hover [class^=\"icon-\"]{ color:#7e8795}\n\t.Hui-aside .menu_dropdown li a{color:#666;border-bottom: 1px solid #e5e5e5}\n\t.Hui-aside .menu_dropdown li a:hover{color:#148cf1;background-color:#fafafa}\n\t.Hui-aside .menu_dropdown li.current a,.menu_dropdown li.current a:hover{color:#148cf1}\n\t.Hui-aside .menu_dropdown dt .Hui-iconfont{ color:#a0a7b1}\n\t.Hui-aside .menu_dropdown dt .menu_dropdown-arrow{ color:#b6b7b8}\t\n\t.dislpayArrow a{background:url(icon_arrow.png) no-repeat 0 0}\n.tabBar {border-bottom: 2px solid #ffd200}\n.tabBar span.current{background-color:#ffd200;color:#282828}"
  },
  {
    "path": "public/static/js/common.js",
    "content": "// window.base={\n//     g_restUrl:'http://115.159.6.199/index.php/api/v1/',\n//\n//     getData:function(params){\n//         if(!params.type){\n//             params.type='get';\n//         }\n//         var that=this;\n//         $.ajax({\n//             type:params.type,\n//             url:this.g_restUrl+params.url,\n//             data:params.data,\n//             beforeSend: function (XMLHttpRequest) {\n//                 if (params.tokenFlag) {\n//                     XMLHttpRequest.setRequestHeader('token', that.getLocalStorage('token'));\n//                 }\n//             },\n//             success:function(res){\n//                 console.log(res);\n//                 params.sCallback && params.sCallback(res);\n//             },\n//             error:function(res){\n//                 console.log(res);\n//                 params.eCallback && params.eCallback(res);\n//             }\n//         });\n//     },\n//\n//     setLocalStorage:function(key,val){\n//         var exp=new Date().getTime()+2*24*60*60*100;  //令牌过期时间\n//         var obj={\n//             val:val,\n//             exp:exp\n//         };\n//         //将json数据转化为字符串，放到缓存中\n//         localStorage.setItem(key,JSON.stringify(obj));\n//     },\n//\n//     getLocalStorage:function(key){\n//         var info= localStorage.getItem(key);\n//         if(info) {\n//             info = JSON.parse(info);\n//             if (info.exp > new Date().getTime()) {\n//                 return info.val;\n//             }\n//             else{\n//                 this.deleteLocalStorage('token');\n//             }\n//         }\n//         return '';\n//     },\n//\n//     deleteLocalStorage:function(key){\n//         return localStorage.removeItem(key);\n//     },\n//\n// }\n\nwindow.base = {\n    g_resultUrl:'http://www.problem.com/index.php/api/v1/',\n\n    getData:function(params) {\n\n        if(!params.type) {\n            params.type = 'Get';\n        }\n        var that = this;\n\n        $.ajax({\n            url:this.g_resultUrl+params.url,\n            type:params.type,\n            data:params.data,\n            beforeSend:function(XMLHttpRequest) {\n                if(params.tokenFlag) {\n                    XMLHttpRequest.setRequestHeader('token',that.getLocalStorage('token'));\n                }\n            },\n            success:function(res) {\n                params.sCallback && params.sCallback(res);\n            },\n            error:function(e){\n                params.eCallback && params.eCallback(e);\n            }\n        })\n    },\n\n    setLocalStorage:function(key,val) {\n        var exp = new Date().getTime() + 2*24*60*60*100;\n\n        var obj = {\n            exp:exp,\n            val:val\n        };\n\n        localStorage.setItem(key,JSON.stringify(obj));\n    },\n\n    getLocalStorage:function(key) {\n\n        var info = localStorage.getItem(key);\n\n        info = JSON.parse(info);\n\n        if(info.exp > new Date().getTime()) {\n            return info.val;\n        }else {\n            this.deleteLocalStorage(key);\n        }\n        return '';\n    },\n\n    deleteLocalStorage:function(key) {\n        return localStorage.removeItem(key);\n    }\n}\n"
  },
  {
    "path": "public/static/js/login.js",
    "content": "$(function(){\n   $(document).on('click','#login',function(){\n       var userName = $('#username'),\n           pwd = $('#password');\n\n       // if(!userName.val()) {\n       //     userName.next().show().find('div').text('用户名不得为空');\n       //     return ;\n       // }\n       // if(!pwd.val()) {\n       //     pwd.next().show().find('div').text('密码不得为空');\n       //     return ;\n       // }\n\n       var params = {\n           url:'token/app',\n           data:{\n               ac:userName.val(),\n               se:pwd.val()\n           },\n           type:'post',\n           sCallback:function(res) {\n               if(res) {\n                   window.base.setLocalStorage('token',res.token);\n                   window.location.href = \"index.html\";\n               }\n           },\n           eCallback:function(res) {\n               if(res.status == 401) {\n                    $('.error-tips').text('帐号或者密码错误').fadeIn().delay(2000).fadeOut();\n                   //$('.error-tips').text('账号和密码错误').show().delay(2000).hide();\n               }\n           }\n       };\n       window.base.getData(params);\n   });\n\n   $(document).on('focus','.normal-input',function(){\n       $('common-error-tips').hide();\n   });\n\n   $(document).on('keydown','.normal-input',function(e){\n       var e = event || window.event || arguments.callee.caller.arguments[0];\n       if(e && e.keyCode == 13)  {\n           $('#login').trigger('click');\n       }\n   })\n});"
  },
  {
    "path": "public/static/js/order.js",
    "content": "$(function(){\n\n    if(!window.base.getLocalStorage('token')){\n        window.location.href = 'login.html';\n    }\n    var pageIndex=1,\n        moreDataFlag=true;\n    getOrders(pageIndex);\n    $('.product-box').hide();\n    /*\n    * 获取数据 分页\n    * params:\n    * pageIndex - {int} 分页下表  1开始\n    */\n\n    function getOrders(pageIndex){\n        var params={\n            url:'order/paginate',\n            data:{page:pageIndex,size:10},\n            tokenFlag:true,\n            sCallback:function(res) {\n                var str = getOrderHtmlStr(res);\n                $('#order-table').append(str);\n            }\n        };\n        window.base.getData(params);\n    }\n\n    /*拼接html字符串*/\n    function getOrderHtmlStr(res){\n        var data = res.data;\n        if (data){\n            var len = data.length,\n                str = '', item;\n            if(len>0) {\n                for (var i = 0; i < len; i++) {\n                    item = data[i];\n                    str += '<tr>' +\n                    '<td style=\"text-align: center\" >'+item.order_no+'</td>'+\n                    '<td style=\"text-align: center\" >'+ item.snap_name +'</td>'+\n                    '<td style=\"text-align: center\" >'+ item.total_count +'</td>'+\n                    '<td style=\"text-align: center\" >￥' + item.total_price + '</td>' +\n                    '<td style=\"text-align: center\"  class=\"td-status\"><span class=\"label label-success radius\">'+getOrderStatus(item.status) +'</span></td>'+\n                    '<td style=\"text-align: center\" >'+ item.create_time +'</td>'+\n                    '<td style=\"text-align: center\"  class=\"td-status\"><span class=\"label label-success radius\">'+getBtns(item.status)+'</span></td>'+\n                        '</tr>';\n                }\n            }\n            else{\n                ctrlLoadMoreBtn();\n                moreDataFlag=false;\n            }\n            return str;\n        }\n        return '';\n    }\n\n    /*根据订单状态获得标志*/\n    function getOrderStatus(status){\n        var arr=[{\n            cName:'unpay',\n            txt:'未付款'\n        },{\n            cName:'payed',\n            txt:'已付款'\n        },{\n            cName:'done',\n            txt:'已发货'\n        },{\n            cName:'unstock',\n            txt:'缺货'\n        }];\n        return '<span class=\"order-status-txt '+arr[status-1].cName+'\">'+arr[status-1].txt+'</span>';\n    }\n\n    /*根据订单状态获得 操作按钮*/\n    function getBtns(status){\n        var arr=[{\n            cName:'done',\n            txt:'发货'\n        },{\n            cName:'unstock',\n            txt:'缺货'\n        }];\n        if(status==2 || status==4){\n            var index=0;\n            if(status==4){\n                index=1;\n            }\n            return '<span class=\"order-btn '+arr[index].cName+'\">'+arr[index].txt+'</span>';\n        }else{\n            return '';\n        }\n    }\n\n    /*控制加载更多按钮的显示*/\n    function ctrlLoadMoreBtn(){\n        if(moreDataFlag) {\n            $('.load-more').hide().next().show();\n        }\n    }\n\n    /*加载更多*/\n    $(document).on('click','.load-more',function(){\n        if(moreDataFlag) {\n            pageIndex++;\n            getOrders(pageIndex);\n        }\n    });\n    /*发货*/\n    $(document).on('click','.order-btn.done',function(){\n        var $this=$(this),\n            $td=$this.closest('td'),\n            $tr=$this.closest('tr'),\n            id=$td.attr('data-id'),\n            $tips=$('.global-tips'),\n            $p=$tips.find('p');\n        var params={\n            url:'order/delivery',\n            type:'put',\n            data:{id:id},\n            tokenFlag:true,\n            sCallback:function(res) {\n                if(res.code.toString().indexOf('2')==0){\n                   $tr.find('.order-status-txt')\n                       .removeClass('pay').addClass('done')\n                       .text('已发货');\n                    $this.remove();\n                    $p.text('操作成功');\n                }else{\n                    $p.text('操作失败');\n                }\n                $tips.show().delay(1500).hide(0);\n            },\n            eCallback:function(){\n                $p.text('操作失败');\n                $tips.show().delay(1500).hide(0);\n            }\n        };\n        window.base.getData(params);\n    });\n\n    /*退出*/\n    $(document).on('click','#login-out',function(){\n        window.base.deleteLocalStorage('token');\n        window.location.href = 'login.html';\n    });\n});"
  },
  {
    "path": "public/static/lib/DD_belatedPNG_0.0.8a-min.js",
    "content": "/**\n* DD_belatedPNG: Adds IE6 support: PNG images for CSS background-image and HTML <IMG/>.\n* Author: Drew Diller\n* Email: drew.diller@gmail.com\n* URL: http://www.dillerdesign.com/experiment/DD_belatedPNG/\n* Version: 0.0.8a\n* Licensed under the MIT License: http://dillerdesign.com/experiment/DD_belatedPNG/#license\n*\n* Example usage:\n* DD_belatedPNG.fix('.png_bg'); // argument is a CSS selector\n* DD_belatedPNG.fixPng( someNode ); // argument is an HTMLDomElement\n**/\nvar DD_belatedPNG={ns:\"DD_belatedPNG\",imgSize:{},delay:10,nodesFixed:0,createVmlNameSpace:function(){if(document.namespaces&&!document.namespaces[this.ns]){document.namespaces.add(this.ns,\"urn:schemas-microsoft-com:vml\")}},createVmlStyleSheet:function(){var b,a;b=document.createElement(\"style\");b.setAttribute(\"media\",\"screen\");document.documentElement.firstChild.insertBefore(b,document.documentElement.firstChild.firstChild);if(b.styleSheet){b=b.styleSheet;b.addRule(this.ns+\"\\\\:*\",\"{behavior:url(#default#VML)}\");b.addRule(this.ns+\"\\\\:shape\",\"position:absolute;\");b.addRule(\"img.\"+this.ns+\"_sizeFinder\",\"behavior:none; border:none; position:absolute; z-index:-1; top:-10000px; visibility:hidden;\");this.screenStyleSheet=b;a=document.createElement(\"style\");a.setAttribute(\"media\",\"print\");document.documentElement.firstChild.insertBefore(a,document.documentElement.firstChild.firstChild);a=a.styleSheet;a.addRule(this.ns+\"\\\\:*\",\"{display: none !important;}\");a.addRule(\"img.\"+this.ns+\"_sizeFinder\",\"{display: none !important;}\")}},readPropertyChange:function(){var b,c,a;b=event.srcElement;if(!b.vmlInitiated){return}if(event.propertyName.search(\"background\")!=-1||event.propertyName.search(\"border\")!=-1){DD_belatedPNG.applyVML(b)}if(event.propertyName==\"style.display\"){c=(b.currentStyle.display==\"none\")?\"none\":\"block\";for(a in b.vml){if(b.vml.hasOwnProperty(a)){b.vml[a].shape.style.display=c}}}if(event.propertyName.search(\"filter\")!=-1){DD_belatedPNG.vmlOpacity(b)}},vmlOpacity:function(b){if(b.currentStyle.filter.search(\"lpha\")!=-1){var a=b.currentStyle.filter;a=parseInt(a.substring(a.lastIndexOf(\"=\")+1,a.lastIndexOf(\")\")),10)/100;b.vml.color.shape.style.filter=b.currentStyle.filter;b.vml.image.fill.opacity=a}},handlePseudoHover:function(a){setTimeout(function(){DD_belatedPNG.applyVML(a)},1)},fix:function(a){if(this.screenStyleSheet){var c,b;c=a.split(\",\");for(b=0;b<c.length;b++){this.screenStyleSheet.addRule(c[b],\"behavior:expression(DD_belatedPNG.fixPng(this))\")}}},applyVML:function(a){a.runtimeStyle.cssText=\"\";this.vmlFill(a);this.vmlOffsets(a);this.vmlOpacity(a);if(a.isImg){this.copyImageBorders(a)}},attachHandlers:function(i){var d,c,g,e,b,f;d=this;c={resize:\"vmlOffsets\",move:\"vmlOffsets\"};if(i.nodeName==\"A\"){e={mouseleave:\"handlePseudoHover\",mouseenter:\"handlePseudoHover\",focus:\"handlePseudoHover\",blur:\"handlePseudoHover\"};for(b in e){if(e.hasOwnProperty(b)){c[b]=e[b]}}}for(f in c){if(c.hasOwnProperty(f)){g=function(){d[c[f]](i)};i.attachEvent(\"on\"+f,g)}}i.attachEvent(\"onpropertychange\",this.readPropertyChange)},giveLayout:function(a){a.style.zoom=1;if(a.currentStyle.position==\"static\"){a.style.position=\"relative\"}},copyImageBorders:function(b){var c,a;c={borderStyle:true,borderWidth:true,borderColor:true};for(a in c){if(c.hasOwnProperty(a)){b.vml.color.shape.style[a]=b.currentStyle[a]}}},vmlFill:function(e){if(!e.currentStyle){return}else{var d,f,g,b,a,c;d=e.currentStyle}for(b in e.vml){if(e.vml.hasOwnProperty(b)){e.vml[b].shape.style.zIndex=d.zIndex}}e.runtimeStyle.backgroundColor=\"\";e.runtimeStyle.backgroundImage=\"\";f=true;if(d.backgroundImage!=\"none\"||e.isImg){if(!e.isImg){e.vmlBg=d.backgroundImage;e.vmlBg=e.vmlBg.substr(5,e.vmlBg.lastIndexOf('\")')-5)}else{e.vmlBg=e.src}g=this;if(!g.imgSize[e.vmlBg]){a=document.createElement(\"img\");g.imgSize[e.vmlBg]=a;a.className=g.ns+\"_sizeFinder\";a.runtimeStyle.cssText=\"behavior:none; position:absolute; left:-10000px; top:-10000px; border:none; margin:0; padding:0;\";c=function(){this.width=this.offsetWidth;this.height=this.offsetHeight;g.vmlOffsets(e)};a.attachEvent(\"onload\",c);a.src=e.vmlBg;a.removeAttribute(\"width\");a.removeAttribute(\"height\");document.body.insertBefore(a,document.body.firstChild)}e.vml.image.fill.src=e.vmlBg;f=false}e.vml.image.fill.on=!f;e.vml.image.fill.color=\"none\";e.vml.color.shape.style.backgroundColor=d.backgroundColor;e.runtimeStyle.backgroundImage=\"none\";e.runtimeStyle.backgroundColor=\"transparent\"},vmlOffsets:function(d){var h,n,a,e,g,m,f,l,j,i,k;h=d.currentStyle;n={W:d.clientWidth+1,H:d.clientHeight+1,w:this.imgSize[d.vmlBg].width,h:this.imgSize[d.vmlBg].height,L:d.offsetLeft,T:d.offsetTop,bLW:d.clientLeft,bTW:d.clientTop};a=(n.L+n.bLW==1)?1:0;e=function(b,p,q,c,s,u){b.coordsize=c+\",\"+s;b.coordorigin=u+\",\"+u;b.path=\"m0,0l\"+c+\",0l\"+c+\",\"+s+\"l0,\"+s+\" xe\";b.style.width=c+\"px\";b.style.height=s+\"px\";b.style.left=p+\"px\";b.style.top=q+\"px\"};e(d.vml.color.shape,(n.L+(d.isImg?0:n.bLW)),(n.T+(d.isImg?0:n.bTW)),(n.W-1),(n.H-1),0);e(d.vml.image.shape,(n.L+n.bLW),(n.T+n.bTW),(n.W),(n.H),1);g={X:0,Y:0};if(d.isImg){g.X=parseInt(h.paddingLeft,10)+1;g.Y=parseInt(h.paddingTop,10)+1}else{for(j in g){if(g.hasOwnProperty(j)){this.figurePercentage(g,n,j,h[\"backgroundPosition\"+j])}}}d.vml.image.fill.position=(g.X/n.W)+\",\"+(g.Y/n.H);m=h.backgroundRepeat;f={T:1,R:n.W+a,B:n.H,L:1+a};l={X:{b1:\"L\",b2:\"R\",d:\"W\"},Y:{b1:\"T\",b2:\"B\",d:\"H\"}};if(m!=\"repeat\"||d.isImg){i={T:(g.Y),R:(g.X+n.w),B:(g.Y+n.h),L:(g.X)};if(m.search(\"repeat-\")!=-1){k=m.split(\"repeat-\")[1].toUpperCase();i[l[k].b1]=1;i[l[k].b2]=n[l[k].d]}if(i.B>n.H){i.B=n.H}d.vml.image.shape.style.clip=\"rect(\"+i.T+\"px \"+(i.R+a)+\"px \"+i.B+\"px \"+(i.L+a)+\"px)\"}else{d.vml.image.shape.style.clip=\"rect(\"+f.T+\"px \"+f.R+\"px \"+f.B+\"px \"+f.L+\"px)\"}},figurePercentage:function(d,c,f,a){var b,e;e=true;b=(f==\"X\");switch(a){case\"left\":case\"top\":d[f]=0;break;case\"center\":d[f]=0.5;break;case\"right\":case\"bottom\":d[f]=1;break;default:if(a.search(\"%\")!=-1){d[f]=parseInt(a,10)/100}else{e=false}}d[f]=Math.ceil(e?((c[b?\"W\":\"H\"]*d[f])-(c[b?\"w\":\"h\"]*d[f])):parseInt(a,10));if(d[f]%2===0){d[f]++}return d[f]},fixPng:function(c){c.style.behavior=\"none\";var g,b,f,a,d;if(c.nodeName==\"BODY\"||c.nodeName==\"TD\"||c.nodeName==\"TR\"){return}c.isImg=false;if(c.nodeName==\"IMG\"){if(c.src.toLowerCase().search(/\\.png$/)!=-1){c.isImg=true;c.style.visibility=\"hidden\"}else{return}}else{if(c.currentStyle.backgroundImage.toLowerCase().search(\".png\")==-1){return}}g=DD_belatedPNG;c.vml={color:{},image:{}};b={shape:{},fill:{}};for(a in c.vml){if(c.vml.hasOwnProperty(a)){for(d in b){if(b.hasOwnProperty(d)){f=g.ns+\":\"+d;c.vml[a][d]=document.createElement(f)}}c.vml[a].shape.stroked=false;c.vml[a].shape.appendChild(c.vml[a].fill);c.parentNode.insertBefore(c.vml[a].shape,c)}}c.vml.image.shape.fillcolor=\"none\";c.vml.image.fill.type=\"tile\";c.vml.color.fill.on=false;g.attachHandlers(c);g.giveLayout(c);g.giveLayout(c.offsetParent);c.vmlInitiated=true;g.applyVML(c)}};try{document.execCommand(\"BackgroundImageCache\",false,true)}catch(r){}DD_belatedPNG.createVmlNameSpace();DD_belatedPNG.createVmlStyleSheet();"
  },
  {
    "path": "public/static/lib/Hui-iconfont/1.0.8/demo.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\"/>\n<title>Hui-iconfont_v1.0.8</title>\n<link href=\"http://static.h-ui.net/h-ui/css/H-ui.min.css\" rel=\"stylesheet\" type=\"text/css\" />\n<link rel=\"stylesheet\" href=\"iconfont.css\">\n<style type=\"text/css\">\n.main {padding: 30px 100px;}\n.main h1{font-size:36px; line-height:1.6; color:#333; text-align:center;margin-bottom:30px; font-weight:normal}\n.main h2{ font-size:24px;line-height:1.6;color:#333;margin-bottom:30px; border-bottom: 1px solid #eee; font-weight:normal}\n\n.helps { margin-top: 40px}\n.helps pre{padding: 20px;margin: 10px 0;border: solid 1px #e7e1cd;background-color: #fffdef;overflow: auto}\n.icon_lists li{float: left;width: 100px;height: 190px;text-align: center}\n.icon_lists .Hui-iconfont{font-size: 42px;line-height: 100px;margin: 10px 0;color: #333;-webkit-transition: font-size 0.25s ease-out 0s;-moz-transition: font-size 0.25s ease-out 0s;transition: font-size 0.25s ease-out 0s}\n.icon_lists .Hui-iconfont:hover { font-size: 100px}\n</style>\n</head>\n<body>\n<div class=\"main\">\n\t<h1>Hui-iconfont_v1.0.8</h1>\n\t<p class=\"text-c c-999\">最后更新日期：2016.06.21  比1.0.7版本增加10个图标</p>\n\t\n\t<h2>操作相关</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe684;</i>\n\t\t\t<div class=\"name\">返回顶部</div>\n\t\t\t<div class=\"code\">&amp;#xe684;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-gotop</div>\n\t\t</li>\n\t\t<li><i class=\"icon Hui-iconfont\">&#xe667;</i>\n            <div class=\"name\">列表</div>\n            <div class=\"code\">&amp;#xe667;</div>\n            <div class=\"fontclass\">.Hui-iconfont-menu</div>\n        </li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe64e;</i>\n\t\t\t<div class=\"name\">剪切</div>\n\t\t\t<div class=\"code\">&amp;#xe64e;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-jiandao</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe665;</i>\n\t\t\t<div class=\"name\">搜索2</div>\n\t\t\t<div class=\"code\">&amp;#xe665;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-search2</div>\n\t\t</li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe709;</i>\n            <div class=\"name\">搜索1</div>\n            <div class=\"code\">&amp;#xe709;</div>\n            <div class=\"fontclass\">.Hui-iconfont-search1</div>\n        </li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe632;</i>\n\t\t\t<div class=\"name\">保存</div>\n\t\t\t<div class=\"code\">&amp;#xe632;</div>\n\t\t\t<div class=\"fontclass\">.save</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe66b;</i>\n\t\t\t<div class=\"name\">撤销</div>\n\t\t\t<div class=\"code\">&amp;#xe66b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-chexiao</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe66c;</i>\n\t\t\t<div class=\"name\">重做</div>\n\t\t\t<div class=\"code\">&amp;#xe66c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-zhongzuo</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe640;</i>\n\t\t\t<div class=\"name\">下载</div>\n\t\t\t<div class=\"code\">&amp;#xe640;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-down</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe63d;</i>\n\t\t\t<div class=\"name\">切换器右</div>\n\t\t\t<div class=\"code\">&amp;#xe63d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-slider-right</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe67d;</i>\n\t\t\t<div class=\"name\">切换器左</div>\n\t\t\t<div class=\"code\">&amp;#xe67d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-slider-left</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe603;</i>\n\t\t\t<div class=\"name\">发布</div>\n\t\t\t<div class=\"code\">&amp;#xe603;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-fabu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe604;</i>\n\t\t\t<div class=\"name\">添加</div>\n\t\t\t<div class=\"code\">&amp;#xe604;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-add2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe68f;</i>\n\t\t\t<div class=\"name\">换一批</div>\n\t\t\t<div class=\"code\">&amp;#xe68f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-huanyipi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe606;</i>\n\t\t\t<div class=\"name\">等待</div>\n\t\t\t<div class=\"code\">&amp;#xe606;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-dengdai</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe644;</i>\n\t\t\t<div class=\"name\">导出</div>\n\t\t\t<div class=\"code\">&amp;#xe644;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-daochu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe645;</i>\n\t\t\t<div class=\"name\">导入</div>\n\t\t\t<div class=\"code\">&amp;#xe645;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-daoru</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe60b;</i>\n\t\t\t<div class=\"name\">删除</div>\n\t\t\t<div class=\"code\">&amp;#xe60b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-del</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe609;</i>\n\t\t\t<div class=\"name\">删除</div>\n\t\t\t<div class=\"code\">&amp;#xe609;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-del2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6e2;</i>\n\t\t\t<div class=\"name\">删除</div>\n\t\t\t<div class=\"code\">&amp;#xe6e2;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-del3</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe647;</i>\n\t\t\t<div class=\"name\">输入</div>\n\t\t\t<div class=\"code\">&amp;#xe647;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-shuru</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe600;</i>\n\t\t\t<div class=\"name\">添加</div>\n\t\t\t<div class=\"code\">&amp;#xe600;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-add</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6a1;</i>\n\t\t\t<div class=\"name\">减号</div>\n\t\t\t<div class=\"code\">&amp;#xe6a1;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-jianhao</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe60c;</i>\n\t\t\t<div class=\"name\">编辑</div>\n\t\t\t<div class=\"code\">&amp;#xe60c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-edit2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6df;</i>\n\t\t\t<div class=\"name\">编辑</div>\n\t\t\t<div class=\"code\">&amp;#xe6df;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-edit</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe61d;</i>\n\t\t\t<div class=\"name\">管理</div>\n\t\t\t<div class=\"code\">&amp;#xe61d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-manage</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe610;</i>\n\t\t\t<div class=\"name\">添加</div>\n\t\t\t<div class=\"code\">&amp;#xe610;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-add3</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe61f;</i>\n\t\t\t<div class=\"name\">添加</div>\n\t\t\t<div class=\"code\">&amp;#xe61f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-add4</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe63f;</i>\n\t\t\t<div class=\"name\">密码</div>\n\t\t\t<div class=\"code\">&amp;#xe63f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-key</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe605;</i>\n\t\t\t<div class=\"name\">解锁</div>\n\t\t\t<div class=\"code\">&amp;#xe605;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-jiesuo</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe60e;</i>\n\t\t\t<div class=\"name\">锁定</div>\n\t\t\t<div class=\"code\">&amp;#xe60e;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-suoding</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6a6;</i>\n\t\t\t<div class=\"name\">关闭</div>\n\t\t\t<div class=\"code\">&amp;#xe6a6;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-close</div>\n\t\t</li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe706;</i>\n            <div class=\"name\">关闭2</div>\n            <div class=\"code\">&amp;#xe706;</div>\n            <div class=\"fontclass\">.Hui-iconfont-close2</div>\n        </li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6a7;</i>\n\t\t\t<div class=\"name\">选择</div>\n\t\t\t<div class=\"code\">&amp;#xe6a7;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-xuanze</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe608;</i>\n\t\t\t<div class=\"name\">未选</div>\n\t\t\t<div class=\"code\">&amp;#xe608;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-weigouxuan2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6a8;</i>\n\t\t\t<div class=\"name\">选中</div>\n\t\t\t<div class=\"code\">&amp;#xe6a8;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-xuanzhong1</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe676;</i>\n\t\t\t<div class=\"name\">选中</div>\n\t\t\t<div class=\"code\">&amp;#xe676;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-xuanzhong</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe677;</i>\n\t\t\t<div class=\"name\">未选中</div>\n\t\t\t<div class=\"code\">&amp;#xe677;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-weixuanzhong</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe601;</i>\n\t\t\t<div class=\"name\">启用</div>\n\t\t\t<div class=\"code\">&amp;#xe601;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-gouxuan2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6f7;</i>\n\t\t\t<div class=\"name\">重启</div>\n\t\t\t<div class=\"code\">&amp;#xe6f7;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-chongqi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe617;</i>\n\t\t\t<div class=\"name\">勾选</div>\n\t\t\t<div class=\"code\">&amp;#xe617;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-selected</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6dc;</i>\n\t\t\t<div class=\"name\">上架</div>\n\t\t\t<div class=\"code\">&amp;#xe6dc;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-shangjia</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6de;</i>\n\t\t\t<div class=\"name\">下架</div>\n\t\t\t<div class=\"code\">&amp;#xe6de;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-xiajia</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe642;</i>\n\t\t\t<div class=\"name\">上传</div>\n\t\t\t<div class=\"code\">&amp;#xe642;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-upload</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe641;</i>\n\t\t\t<div class=\"name\">下载</div>\n\t\t\t<div class=\"code\">&amp;#xe641;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-yundown</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6bc;</i>\n\t\t\t<div class=\"name\">剪裁</div>\n\t\t\t<div class=\"code\">&amp;#xe6bc;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-caiqie</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6bd;</i>\n\t\t\t<div class=\"name\">旋转</div>\n\t\t\t<div class=\"code\">&amp;#xe6bd;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-xuanzhuan</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe615;</i>\n\t\t\t<div class=\"name\">启用</div>\n\t\t\t<div class=\"code\">&amp;#xe615;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-gouxuan</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6e1;</i>\n\t\t\t<div class=\"name\">未勾选</div>\n\t\t\t<div class=\"code\">&amp;#xe614;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-weigouxuan</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe619;</i>\n\t\t\t<div class=\"name\">录音</div>\n\t\t\t<div class=\"code\">&amp;#xe619;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-luyin</div>\n\t\t</li>\n\t\t\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe695;</i>\n\t\t\t<div class=\"name\">预览</div>\n\t\t\t<div class=\"code\">&amp;#xe695;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-yulan</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6e0;</i>\n\t\t\t<div class=\"name\">审核不通过</div>\n\t\t\t<div class=\"code\">&amp;#xe6e0;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-shenhe-weitongguo</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6dd;</i>\n\t\t\t<div class=\"name\">审核不通过</div>\n\t\t\t<div class=\"code\">&amp;#xe6dd;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-shenhe-butongguo2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6e1;</i>\n\t\t\t<div class=\"name\">审核通过</div>\n\t\t\t<div class=\"code\">&amp;#xe6e1;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-shenhe-tongguo</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe631;</i>\n\t\t\t<div class=\"name\">停用</div>\n\t\t\t<div class=\"code\">&amp;#xe631;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-shenhe-tingyong</div>\n\t\t</li>\n\t\t<li>\n            <i class=\"icon Hui-iconfont\">&#xe6e6;</i>\n            <div class=\"name\">播放</div>\n            <div class=\"code\">&amp;#xe6e6;</div>\n            <div class=\"fontclass\">.Hui-iconfont-bofang</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6db;</i>\n            <div class=\"name\">上一首</div>\n            <div class=\"code\">&amp;#xe6db;</div>\n            <div class=\"fontclass\">.Hui-iconfont-shangyishou</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6e3;</i>\n            <div class=\"name\">下一首</div>\n            <div class=\"code\">&amp;#xe6e3;</div>\n            <div class=\"fontclass\">.Hui-iconfont-xiayishou</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6e5;</i>\n            <div class=\"name\">暂停</div>\n            <div class=\"code\">&amp;#xe6e5;</div>\n            <div class=\"fontclass\">.Hui-iconfont-zanting</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6e4;</i>\n            <div class=\"name\">停止</div>\n            <div class=\"code\">&amp;#xe6e4;</div>\n            <div class=\"fontclass\">.Hui-iconfont-tingzhi</div>\n        </li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe720;</i>\n\t\t\t<div class=\"name\">阅读</div>\n\t\t\t<div class=\"code\">&amp;#xe720;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-yuedu</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe725;</i>\n\t\t\t<div class=\"name\">眼睛</div>\n\t\t\t<div class=\"code\">&amp;#xe725;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-yanjing</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe726;</i>\n\t\t\t<div class=\"name\">电源</div>\n\t\t\t<div class=\"code\">&amp;#xe726;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-power</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe72a;</i>\n\t\t\t<div class=\"name\">图标2_橡皮擦</div>\n\t\t\t<div class=\"code\">&amp;#xe72a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-xiangpicha</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe728;</i>\n\t\t\t<div class=\"name\">计时器</div>\n\t\t\t<div class=\"code\">&amp;#xe728;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-jishiqi</div>\n\t\t</li>\n\t\t\n\t</ul>\n\t<h2>菜单相关</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe625;</i>\n\t\t\t<div class=\"name\">home</div>\n\t\t\t<div class=\"code\">&amp;#xe625;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-home</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe67f;</i>\n\t\t\t<div class=\"name\">小箭头</div>\n\t\t\t<div class=\"code\">&amp;#xe67f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-home2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe616;</i>\n\t\t\t<div class=\"name\">cmstop新闻</div>\n\t\t\t<div class=\"code\">&amp;#xe616;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-news</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe613;</i>\n\t\t\t<div class=\"name\">图片</div>\n\t\t\t<div class=\"code\">&amp;#xe613;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tuku</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe60f;</i>\n\t\t\t<div class=\"name\">音乐</div>\n\t\t\t<div class=\"code\">&amp;#xe60f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-music</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe64b;</i>\n\t\t\t<div class=\"name\">标签</div>\n\t\t\t<div class=\"code\">&amp;#xe64b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tags</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe66f;</i>\n\t\t\t<div class=\"name\">语音</div>\n\t\t\t<div class=\"code\">&amp;#xe66f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-yuyin3</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe62e;</i>\n\t\t\t<div class=\"name\">系统</div>\n\t\t\t<div class=\"code\">&amp;#xe62e;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-system</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe633;</i>\n\t\t\t<div class=\"name\">帮助</div>\n\t\t\t<div class=\"code\">&amp;#xe633;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-help</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe634;</i>\n\t\t\t<div class=\"name\">出库</div>\n\t\t\t<div class=\"code\">&amp;#xe634;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-chuku</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe646;</i>\n\t\t\t<div class=\"name\">图片</div>\n\t\t\t<div class=\"code\">&amp;#xe646;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-picture</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe681;</i>\n\t\t\t<div class=\"name\">分类</div>\n\t\t\t<div class=\"code\">&amp;#xe681;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-fenlei</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe636;</i>\n\t\t\t<div class=\"name\">合同管理</div>\n\t\t\t<div class=\"code\">&amp;#xe636;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-hetong</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe687;</i>\n\t\t\t<div class=\"name\">全部订单</div>\n\t\t\t<div class=\"code\">&amp;#xe687;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-quanbudingdan</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe637;</i>\n\t\t\t<div class=\"name\">任务管理</div>\n\t\t\t<div class=\"code\">&amp;#xe637;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-renwu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe691;</i>\n\t\t\t<div class=\"name\">问题反馈</div>\n\t\t\t<div class=\"code\">&amp;#xe691;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-feedback</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe692;</i>\n\t\t\t<div class=\"name\">意见反馈</div>\n\t\t\t<div class=\"code\">&amp;#xe692;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-feedback2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe639;</i>\n\t\t\t<div class=\"name\">合同</div>\n\t\t\t<div class=\"code\">&amp;#xe639;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-dangan</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe623;</i>\n\t\t\t<div class=\"name\">日志</div>\n\t\t\t<div class=\"code\">&amp;#xe623;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-log</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe626;</i>\n\t\t\t<div class=\"name\">列表页面</div>\n\t\t\t<div class=\"code\">&amp;#xe626;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-pages</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe63e;</i>\n\t\t\t<div class=\"name\">文件</div>\n\t\t\t<div class=\"code\">&amp;#xe63e;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-file</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe63c;</i>\n\t\t\t<div class=\"name\">管理</div>\n\t\t\t<div class=\"code\">&amp;#xe63c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-manage2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe627;</i>\n\t\t\t<div class=\"name\">订单</div>\n\t\t\t<div class=\"code\">&amp;#xe627;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-order</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6a4;</i>\n\t\t\t<div class=\"name\">语音</div>\n\t\t\t<div class=\"code\">&amp;#xe6a4;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-yuyin2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6a5;</i>\n\t\t\t<div class=\"name\">语音</div>\n\t\t\t<div class=\"code\">&amp;#xe6a5;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-yuyin</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe612;</i>\n\t\t\t<div class=\"name\">图片</div>\n\t\t\t<div class=\"code\">&amp;#xe612;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-picture1</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe685;</i>\n\t\t\t<div class=\"name\">图文详情</div>\n\t\t\t<div class=\"code\">&amp;#xe685;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tuwenxiangqing</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe72d;</i>\n\t\t\t<div class=\"name\">模版</div>\n\t\t\t<div class=\"code\">&amp;#xe72d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-moban-2</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe727;</i>\n\t\t\t<div class=\"name\">节日</div>\n\t\t\t<div class=\"code\">&amp;#xe727;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-jieri</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe72b;</i>\n\t\t\t<div class=\"name\">随你后台-网站</div>\n\t\t\t<div class=\"code\">&amp;#xe72b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-moban</div>\n\t\t</li>\n\t</ul>\n\t<h2>天气相关</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6ac;</i>\n\t\t\t<div class=\"name\">多云</div>\n\t\t\t<div class=\"code\">&amp;#xe6ac;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tianqi-duoyun</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6ad;</i>\n\t\t\t<div class=\"name\">霾</div>\n\t\t\t<div class=\"code\">&amp;#xe6ad;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tianqi-mai</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6ae;</i>\n\t\t\t<div class=\"name\">晴</div>\n\t\t\t<div class=\"code\">&amp;#xe6ae;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tianqi-qing</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6af;</i>\n\t\t\t<div class=\"name\">雾</div>\n\t\t\t<div class=\"code\">&amp;#xe6af;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tianqi-wu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6b0;</i>\n\t\t\t<div class=\"name\">雪</div>\n\t\t\t<div class=\"code\">&amp;#xe6b0;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tianqi-xue</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6b1;</i>\n\t\t\t<div class=\"name\">阴</div>\n\t\t\t<div class=\"code\">&amp;#xe6b1;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tianqi-yin</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6b2;</i>\n\t\t\t<div class=\"name\">雨</div>\n\t\t\t<div class=\"code\">&amp;#xe6b2;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tianqi-yu</div>\n\t\t</li>\n\t</ul>\n\t<h2>用户相关</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe62c;</i>\n\t\t\t<div class=\"name\">用户</div>\n\t\t\t<div class=\"code\">&amp;#xe62c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-user</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe60d;</i>\n\t\t\t<div class=\"name\">用户</div>\n\t\t\t<div class=\"code\">&amp;#xe60d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-user2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe60a;</i>\n\t\t\t<div class=\"name\">用户头像</div>\n\t\t\t<div class=\"code\">&amp;#xe60a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-avatar</div>\n\t\t</li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe705;</i>\n            <div class=\"name\">个人中心</div>\n            <div class=\"code\">&amp;#xe705;</div>\n            <div class=\"fontclass\">.Hui-iconfont-avatar2</div>\n        </li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe607;</i>\n\t\t\t<div class=\"name\">添加用户</div>\n\t\t\t<div class=\"code\">&amp;#xe607;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-user-add</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe602;</i>\n\t\t\t<div class=\"name\">用户ID</div>\n\t\t\t<div class=\"code\">&amp;#xe602;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-userid</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe638;</i>\n\t\t\t<div class=\"name\">证照管理</div>\n\t\t\t<div class=\"code\">&amp;#xe638;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-zhizhao</div>\n\t\t</li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe70d;</i>\n            <div class=\"name\">执业证</div>\n            <div class=\"code\">&amp;#xe70d;</div>\n            <div class=\"fontclass\">.Hui-iconfont-practice</div>\n        </li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe62b;</i>\n\t\t\t<div class=\"name\">群组</div>\n\t\t\t<div class=\"code\">&amp;#xe62b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-user-group</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe653;</i>\n\t\t\t<div class=\"name\">站长</div>\n\t\t\t<div class=\"code\">&amp;#xe653;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-user-zhanzhang</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe62d;</i>\n\t\t\t<div class=\"name\">管理员</div>\n\t\t\t<div class=\"code\">&amp;#xe62d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-root</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe643;</i>\n\t\t\t<div class=\"name\">公司</div>\n\t\t\t<div class=\"code\">&amp;#xe643;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-gongsi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6b4;</i>\n\t\t\t<div class=\"name\">会员卡</div>\n\t\t\t<div class=\"code\">&amp;#xe6b4;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-vip-card2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6cc;</i>\n\t\t\t<div class=\"name\">会员</div>\n\t\t\t<div class=\"code\">&amp;#xe6cc;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-vip</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe611;</i>\n\t\t\t<div class=\"name\">群组</div>\n\t\t\t<div class=\"code\">&amp;#xe611;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-usergroup2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6d0;</i>\n\t\t\t<div class=\"name\">客服</div>\n\t\t\t<div class=\"code\">&amp;#xe6d0;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-kefu</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe72c;</i>\n\t\t\t<div class=\"name\">版主</div>\n\t\t\t<div class=\"code\">&amp;#xe72c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-banzhu</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe6d3;</i>\n\t\t\t<div class=\"name\">皇冠</div>\n\t\t\t<div class=\"code\">&amp;#xe6d3;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-huangguan</div>\n\t\t</li>\n\t</ul>\n\t<h2>表情相关</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe68e;</i>\n\t\t\t<div class=\"name\">表情</div>\n\t\t\t<div class=\"code\">&amp;#xe68e;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe668;</i>\n\t\t\t<div class=\"name\">表情</div>\n\t\t\t<div class=\"code\">&amp;#xe668;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe656;</i>\n\t\t\t<div class=\"name\">微笑</div>\n\t\t\t<div class=\"code\">&amp;#xe656;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-weixiao</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe688;</i>\n\t\t\t<div class=\"name\">哭脸</div>\n\t\t\t<div class=\"code\">&amp;#xe688;</div>\n\t\t\t<div class=\"fontclass\">.face-ku</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe657;</i>\n\t\t\t<div class=\"name\">吃惊</div>\n\t\t\t<div class=\"code\">&amp;#xe657;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-chijing</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe658;</i>\n\t\t\t<div class=\"name\">呆</div>\n\t\t\t<div class=\"code\">&amp;#xe658;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-dai</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe659;</i>\n\t\t\t<div class=\"name\">耍酷</div>\n\t\t\t<div class=\"code\">&amp;#xe659;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-shuaku</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe65a;</i>\n\t\t\t<div class=\"name\">魔鬼</div>\n\t\t\t<div class=\"code\">&amp;#xe65a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-mogui</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe65b;</i>\n\t\t\t<div class=\"name\">尴尬</div>\n\t\t\t<div class=\"code\">&amp;#xe65b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-ganga</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe65c;</i>\n\t\t\t<div class=\"name\">亲</div>\n\t\t\t<div class=\"code\">&amp;#xe65c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-qin</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe65d;</i>\n\t\t\t<div class=\"name\">怒</div>\n\t\t\t<div class=\"code\">&amp;#xe65d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-nu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe65e;</i>\n\t\t\t<div class=\"name\">眨眼</div>\n\t\t\t<div class=\"code\">&amp;#xe65e;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-zhayan</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe65f;</i>\n\t\t\t<div class=\"name\">生气</div>\n\t\t\t<div class=\"code\">&amp;#xe65f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-shengqi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe660;</i>\n\t\t\t<div class=\"name\">骂</div>\n\t\t\t<div class=\"code\">&amp;#xe660;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-ma</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe661;</i>\n\t\t\t<div class=\"name\">鄙视</div>\n\t\t\t<div class=\"code\">&amp;#xe661;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-bishi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe662;</i>\n\t\t\t<div class=\"name\">卖萌</div>\n\t\t\t<div class=\"code\">&amp;#xe662;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-maimeng</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe663;</i>\n\t\t\t<div class=\"name\">惊呆</div>\n\t\t\t<div class=\"code\">&amp;#xe663;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-jingdai</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe664;</i>\n\t\t\t<div class=\"name\">晕</div>\n\t\t\t<div class=\"code\">&amp;#xe664;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-face-yun</div>\n\t\t</li>\n\t</ul>\n\t<h2>社区相关</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe666;</i>\n\t\t\t<div class=\"name\">分享</div>\n\t\t\t<div class=\"code\">&amp;#xe666;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6aa;</i>\n\t\t\t<div class=\"name\">分享</div>\n\t\t\t<div class=\"code\">&amp;#xe6aa;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6d8;</i>\n\t\t\t<div class=\"name\">人人网</div>\n\t\t\t<div class=\"code\">&amp;#xe6d8;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share-renren</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6d9;</i>\n\t\t\t<div class=\"name\">腾讯微博</div>\n\t\t\t<div class=\"code\">&amp;#xe6d9;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share-tweibo</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe67c;</i>\n\t\t\t<div class=\"name\">豆瓣</div>\n\t\t\t<div class=\"code\">&amp;#xe67c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share-douban</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe693;</i>\n\t\t\t<div class=\"name\">朋友圈</div>\n\t\t\t<div class=\"code\">&amp;#xe693;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share-pengyouquan</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe694;</i>\n\t\t\t<div class=\"name\">微信</div>\n\t\t\t<div class=\"code\">&amp;#xe694;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share-weixin</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe67b;</i>\n\t\t\t<div class=\"name\">QQ</div>\n\t\t\t<div class=\"code\">&amp;#xe67b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share-qq</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe6c8;</i>\n\t\t\t<div class=\"name\">QQ空间</div>\n\t\t\t<div class=\"code\">&amp;#xe6c8;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share-qzone</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe6da;</i>\n\t\t\t<div class=\"name\">微博</div>\n\t\t\t<div class=\"code\">&amp;#xe6da;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share-weibo</div>\n\t\t</li>\n\t\t\t<li> <i class=\"icon Hui-iconfont\">&#xe689;</i>\n\t\t\t<div class=\"name\">知乎</div>\n\t\t\t<div class=\"code\">&amp;#xe689;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-share-zhihu</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe715;</i>\n\t\t\t<div class=\"name\">更多</div>\n\t\t\t<div class=\"code\">&amp;#xe715;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-gengduo</div>\n\t\t</li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe716;</i>\n            <div class=\"name\">更多</div>\n            <div class=\"code\">&amp;#xe716;</div>\n            <div class=\"fontclass\">.Hui-iconfont-gengduo2</div>\n        </li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6f9;</i>\n            <div class=\"name\">更多</div>\n            <div class=\"code\">&amp;#xe6f9;</div>\n            <div class=\"fontclass\">.Hui-iconfont-engduo3</div>\n        </li>\n         <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe717;</i>\n            <div class=\"name\">更多</div>\n            <div class=\"code\">&amp;#xe717;</div>\n            <div class=\"fontclass\">.Hui-iconfont-gengduo4</div>\n        </li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe649;</i>\n\t\t\t<div class=\"name\">喜欢</div>\n\t\t\t<div class=\"code\">&amp;#xe649;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-like</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe648;</i>\n\t\t\t<div class=\"name\">喜欢</div>\n\t\t\t<div class=\"code\">&amp;#xe648;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-like2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe680;</i>\n\t\t\t<div class=\"name\">已关注</div>\n\t\t\t<div class=\"code\">&amp;#xe680;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-yiguanzhu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe622;</i>\n\t\t\t<div class=\"name\">评论</div>\n\t\t\t<div class=\"code\">&amp;#xe622;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-comment</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe686;</i>\n\t\t\t<div class=\"name\">累计评价</div>\n\t\t\t<div class=\"code\">&amp;#xe686;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-leijipingjia</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe68a;</i>\n\t\t\t<div class=\"name\">消息</div>\n\t\t\t<div class=\"code\">&amp;#xe68a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-xiaoxi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe61b;</i>\n\t\t\t<div class=\"name\">收藏</div>\n\t\t\t<div class=\"code\">&amp;#xe61b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-cang</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe630;</i>\n\t\t\t<div class=\"name\">收藏-选中</div>\n\t\t\t<div class=\"code\">&amp;#xe630;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-cang-selected</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe69e;</i>\n\t\t\t<div class=\"name\">收藏</div>\n\t\t\t<div class=\"code\">&amp;#xe69e;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-cang2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe69d;</i>\n\t\t\t<div class=\"name\">收藏-选中</div>\n\t\t\t<div class=\"code\">&amp;#xe69d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-cang2-selected</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe68b;</i>\n\t\t\t<div class=\"name\">关注-更多操作</div>\n\t\t\t<div class=\"code\">&amp;#xe68b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-more</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe66d;</i>\n\t\t\t<div class=\"name\">赞扬</div>\n\t\t\t<div class=\"code\">&amp;#xe66d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-zan</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe66e;</i>\n\t\t\t<div class=\"name\">批评</div>\n\t\t\t<div class=\"code\">&amp;#xe66e;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-cai</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe697;</i>\n\t\t\t<div class=\"name\">点赞</div>\n\t\t\t<div class=\"code\">&amp;#xe697;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-zan2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe62f;</i>\n\t\t\t<div class=\"name\">通知</div>\n\t\t\t<div class=\"code\">&amp;#xe62f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-msg</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe63b;</i>\n\t\t\t<div class=\"name\">消息管理</div>\n\t\t\t<div class=\"code\">&amp;#xe63b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-email</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6a9;</i>\n\t\t\t<div class=\"name\">已关注店铺</div>\n\t\t\t<div class=\"code\">&amp;#xe6a9;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-yiguanzhu1</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6ab;</i>\n\t\t\t<div class=\"name\">转发</div>\n\t\t\t<div class=\"code\">&amp;#xe6ab;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-zhuanfa</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6b3;</i>\n\t\t\t<div class=\"name\">待评价</div>\n\t\t\t<div class=\"code\">&amp;#xe6b3;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-daipingjia</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6b5;</i>\n\t\t\t<div class=\"name\">积分</div>\n\t\t\t<div class=\"code\">&amp;#xe6b5;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-jifen</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6c5;</i>\n\t\t\t<div class=\"name\">消息</div>\n\t\t\t<div class=\"code\">&amp;#xe6c5;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-xiaoxi1</div>\n\t\t</li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe70b;</i>\n            <div class=\"name\">已读</div>\n            <div class=\"code\">&amp;#xe70b;</div>\n            <div class=\"fontclass\">.Hui-iconfont-read</div>\n        </li>\n    \n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe70c;</i>\n            <div class=\"name\">用户反馈</div>\n            <div class=\"code\">&amp;#xe70c;</div>\n            <div class=\"fontclass\">.Hui-iconfont-feedback1</div>\n        </li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6ce;</i>\n\t\t\t<div class=\"name\">订阅</div>\n\t\t\t<div class=\"code\">&amp;#xe6ce;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-dingyue</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6cd;</i>\n\t\t\t<div class=\"name\">提示</div>\n\t\t\t<div class=\"code\">&amp;#xe6cd;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tishi</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe702;</i>\n            <div class=\"name\">star-o</div>\n            <div class=\"code\">&amp;#xe702;</div>\n            <div class=\"fontclass\">.Hui-iconfont-star-o</div>\n        </li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe6ff;</i>\n            <div class=\"name\">star</div>\n            <div class=\"code\">&amp;#xe6ff;</div>\n            <div class=\"fontclass\">.Hui-iconfont-star</div>\n        </li>\n        <li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe700;</i>\n            <div class=\"name\">star-half</div>\n            <div class=\"code\">&amp;#xe700;</div>\n            <div class=\"fontclass\">.Hui-iconfont-star-half</div>\n        </li>\n        <li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe701;</i>\n            <div class=\"name\">star-half-empty</div>\n            <div class=\"code\">&amp;#xe701;</div>\n            <div class=\"fontclass\">.Hui-iconfont-star-halfempty</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe70a;</i>\n            <div class=\"name\">我的评价</div>\n            <div class=\"code\">&amp;#xe70a;</div>\n            <div class=\"fontclass\">.Hui-iconfont-comment1</div>\n        </li>\n\t</ul>\n\t<h2>统计相关</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe621;</i>\n\t\t\t<div class=\"name\">数据统计</div>\n\t\t\t<div class=\"code\">&amp;#xe621;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tongji-bing</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe635;</i>\n\t\t\t<div class=\"name\">统计管理</div>\n\t\t\t<div class=\"code\">&amp;#xe635;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-ad</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe61e;</i>\n\t\t\t<div class=\"name\">数据统计</div>\n\t\t\t<div class=\"code\">&amp;#xe61e;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-shujutongji</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe61a;</i>\n\t\t\t<div class=\"name\">统计</div>\n\t\t\t<div class=\"code\">&amp;#xe61a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tongji</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe618;</i>\n\t\t\t<div class=\"name\">柱状统计</div>\n\t\t\t<div class=\"code\">&amp;#xe618;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tongji-zhu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe61c;</i>\n\t\t\t<div class=\"name\">线状统计</div>\n\t\t\t<div class=\"code\">&amp;#xe61c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tongji-xian</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6cf;</i>\n\t\t\t<div class=\"name\">排行榜</div>\n\t\t\t<div class=\"code\">&amp;#xe6cf;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-paixingbang</div>\n\t\t</li>\n\t</ul>\n\t<h2>箭头相关</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe678;</i>\n\t\t\t<div class=\"name\">向左</div>\n\t\t\t<div class=\"code\">&amp;#xe678;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow1-bottom</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe674;</i>\n\t\t\t<div class=\"name\">向下</div>\n\t\t\t<div class=\"code\">&amp;#xe674;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow1-bottom</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe679;</i>\n\t\t\t<div class=\"name\">向上</div>\n\t\t\t<div class=\"code\">&amp;#xe679;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow1-top</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe67a;</i>\n\t\t\t<div class=\"name\">向右</div>\n\t\t\t<div class=\"code\">&amp;#xe67a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow1-right</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6d4;</i>\n\t\t\t<div class=\"name\">向左</div>\n\t\t\t<div class=\"code\">&amp;#xe6d4;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow2-left</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6d6;</i>\n\t\t\t<div class=\"name\">向上</div>\n\t\t\t<div class=\"code\">&amp;#xe6d6;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow2-top</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6d7;</i>\n\t\t\t<div class=\"name\">向右</div>\n\t\t\t<div class=\"code\">&amp;#xe6d7;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow2-right</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6d5;</i>\n\t\t\t<div class=\"name\">向下</div>\n\t\t\t<div class=\"code\">&amp;#xe6d5;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow2-bottom</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe69b;</i>\n\t\t\t<div class=\"name\">向左</div>\n\t\t\t<div class=\"code\">&amp;#xe69b;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow3-left</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe699;</i>\n\t\t\t<div class=\"name\">向上</div>\n\t\t\t<div class=\"code\">&amp;#xe699;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow3-top</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe69a;</i>\n\t\t\t<div class=\"name\">向右</div>\n\t\t\t<div class=\"code\">&amp;#xe69a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow3-right</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe698;</i>\n\t\t\t<div class=\"name\">向下</div>\n\t\t\t<div class=\"code\">&amp;#xe698;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-arrow3-bottom</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe67e;</i>\n\t\t\t<div class=\"name\">向右</div>\n\t\t\t<div class=\"code\">&amp;#xe67e;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-sanjiao</div>\n\t\t</li>\n\t</ul>\n\t<h2>电商相关</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe669;</i>\n\t\t\t<div class=\"name\">物流</div>\n\t\t\t<div class=\"code\">&amp;#xe669;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-wuliu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe66a;</i>\n\t\t\t<div class=\"name\">店铺</div>\n\t\t\t<div class=\"code\">&amp;#xe66a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-dianpu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe670;</i>\n\t\t\t<div class=\"name\">购物车</div>\n\t\t\t<div class=\"code\">&amp;#xe670;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-cart2-selected</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe672;</i>\n\t\t\t<div class=\"name\">购物车满</div>\n\t\t\t<div class=\"code\">&amp;#xe672;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-cart2-man</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe673;</i>\n\t\t\t<div class=\"name\">购物车空</div>\n\t\t\t<div class=\"code\">&amp;#xe673;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-card2-kong</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6b8;</i>\n\t\t\t<div class=\"name\">购物车-选中</div>\n\t\t\t<div class=\"code\">&amp;#xe6b8;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-cart-selected</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6b9;</i>\n\t\t\t<div class=\"name\">购物车</div>\n\t\t\t<div class=\"code\">&amp;#xe6b9;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-cart-kong</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6ba;</i>\n\t\t\t<div class=\"name\">降价</div>\n\t\t\t<div class=\"code\">&amp;#xe6ba;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-jiangjia</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe628;</i>\n\t\t\t<div class=\"name\">信用卡还款</div>\n\t\t\t<div class=\"code\">&amp;#xe628;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-bank</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6bb;</i>\n\t\t\t<div class=\"name\">礼物</div>\n\t\t\t<div class=\"code\">&amp;#xe6bb;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-liwu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6b6;</i>\n\t\t\t<div class=\"name\">优惠券</div>\n\t\t\t<div class=\"code\">&amp;#xe6b6;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-youhuiquan</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6b7;</i>\n\t\t\t<div class=\"name\">红包</div>\n\t\t\t<div class=\"code\">&amp;#xe6b7;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-hongbao</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6ca;</i>\n\t\t\t<div class=\"name\">优惠券</div>\n\t\t\t<div class=\"code\">&amp;#xe6ca;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-hongbao2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe63a;</i>\n\t\t\t<div class=\"name\">资金</div>\n\t\t\t<div class=\"code\">&amp;#xe63a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-money</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe620;</i>\n\t\t\t<div class=\"name\">商品</div>\n\t\t\t<div class=\"code\">&amp;#xe620;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-goods</div>\n\t\t</li>\n\t</ul>\n\t<h2>编辑器</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6ee;</i>\n            <div class=\"name\">code</div>\n            <div class=\"code\">&amp;#xe6ee;</div>\n            <div class=\"fontclass\">.Hui-iconfont-code</div>\n        </li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe710;</i>\n            <div class=\"name\">左对齐</div>\n            <div class=\"code\">&amp;#xe710;</div>\n            <div class=\"fontclass\">.Hui-iconfont-align-left</div>\n        </li>\n    \t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe70e;</i>\n            <div class=\"name\">居中对齐</div>\n            <div class=\"code\">&amp;#xe70e;</div>\n            <div class=\"fontclass\">.Hui-iconfont-align-center</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe711;</i>\n            <div class=\"name\">右对齐</div>\n            <div class=\"code\">&amp;#xe711;</div>\n            <div class=\"fontclass\">.Hui-iconfont-align-right</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe70f;</i>\n            <div class=\"name\">两头对齐</div>\n            <div class=\"code\">&amp;#xe70f;</div>\n            <div class=\"fontclass\">.Hui-iconfont-align-justify</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6ec;</i>\n            <div class=\"name\">字体</div>\n            <div class=\"code\">&amp;#xe6ec;</div>\n            <div class=\"fontclass\">.Hui-iconfont-font</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6e7;</i>\n            <div class=\"name\">加粗</div>\n            <div class=\"code\">&amp;#xe6e7;</div>\n            <div class=\"fontclass\">.Hui-iconfont-bold</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6e9;</i>\n            <div class=\"name\">倾斜</div>\n            <div class=\"code\">&amp;#xe6e9;</div>\n            <div class=\"fontclass\">.Hui-iconfont-italic</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6fe;</i>\n            <div class=\"name\">下划线</div>\n            <div class=\"code\">&amp;#xe6fe;</div>\n            <div class=\"fontclass\">.Hui-iconfont-underline</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6fc;</i>\n            <div class=\"name\">text-height</div>\n            <div class=\"code\">&amp;#xe6fc;</div>\n            <div class=\"fontclass\">.Hui-iconfont-text-height</div>\n        </li>\n    \n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6fd;</i>\n            <div class=\"name\">text-width</div>\n            <div class=\"code\">&amp;#xe6fd;</div>\n            <div class=\"fontclass\">.Hui-iconfont-text-width</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6f1;</i>\n            <div class=\"name\">link</div>\n            <div class=\"code\">&amp;#xe6f1;</div>\n            <div class=\"fontclass\">.Hui-iconfont-link</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6f3;</i>\n            <div class=\"name\">有序列表</div>\n            <div class=\"code\">&amp;#xe6f3;</div>\n            <div class=\"fontclass\">.Hui-iconfont-ordered-list</div>\n        </li>\n    \n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6f5;</i>\n            <div class=\"name\">无序列表</div>\n            <div class=\"code\">&amp;#xe6f5;</div>\n            <div class=\"fontclass\">.Hui-iconfont-unordered-list</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6ef;</i>\n            <div class=\"name\">剪切</div>\n            <div class=\"code\">&amp;#xe6ef;</div>\n            <div class=\"fontclass\">.Hui-iconfont-cut</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6ea;</i>\n            <div class=\"name\">复制</div>\n            <div class=\"code\">&amp;#xe6ea;</div>\n            <div class=\"fontclass\">.Hui-iconfont-copy</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6eb;</i>\n            <div class=\"name\">粘贴</div>\n            <div class=\"code\">&amp;#xe6eb;</div>\n            <div class=\"fontclass\">.Hui-iconfont-paste</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6f2;</i>\n            <div class=\"name\">新建</div>\n            <div class=\"code\">&amp;#xe6f2;</div>\n            <div class=\"fontclass\">.Hui-iconfont-new</div>\n        </li>\n\t</ul>\n\t<h2>银行、支付相关</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe71f;</i>\n\t\t\t<div class=\"name\">支付宝支付1</div>\n\t\t\t<div class=\"code\">&amp;#xe71f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-pay-alipay-1</div>\n\t\t</li>  \n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe71c;</i>\n\t\t\t<div class=\"name\">支付宝支付2</div>\n\t\t\t<div class=\"code\">&amp;#xe71c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-pay-alipay-2</div>\n\t\t</li>\n\t\t<li>\n\t\t\t<i class=\"icon Hui-iconfont\">&#xe719;</i>\n\t\t\t<div class=\"name\">微信支付</div>\n\t\t\t<div class=\"code\">&amp;#xe719;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-pay-weixin</div>\n\t\t</li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe722;</i>\n            <div class=\"name\">中国银行</div>\n            <div class=\"code\">&amp;#xe722;</div>\n            <div class=\"fontclass\">.Hui-iconfont-zhongguoyinxing</div>\n        </li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe71d;</i>\n            <div class=\"name\">工商银行</div>\n            <div class=\"code\">&amp;#xe71d;</div>\n            <div class=\"fontclass\">.Hui-iconfont-gongshangyinxing</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6f8;</i>\n            <div class=\"name\">建设银行</div>\n            <div class=\"code\">&amp;#xe6f8;</div>\n            <div class=\"fontclass\">.Hui-iconfont-jiansheyinxing</div>\n        </li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe71a;</i>\n            <div class=\"name\">交通银行</div>\n            <div class=\"code\">&amp;#xe71a;</div>\n            <div class=\"fontclass\">.Hui-iconfont-jiaotongyinxing</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe713;</i>\n            <div class=\"name\">中国农业银行</div>\n            <div class=\"code\">&amp;#xe713;</div>\n            <div class=\"fontclass\">.Hui-iconfont-zhongguonongyeyinxing</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe721;</i>\n            <div class=\"name\">邮政银行</div>\n            <div class=\"code\">&amp;#xe721;</div>\n            <div class=\"fontclass\">.Hui-iconfont-youzhengyinxing</div>\n        </li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe71b;</i>\n            <div class=\"name\">浦发银行</div>\n            <div class=\"code\">&amp;#xe71b;</div>\n            <div class=\"fontclass\">.Hui-iconfont-pufayinxing</div>\n        </li>  \n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe71e;</i>\n            <div class=\"name\">华夏银行</div>\n            <div class=\"code\">&amp;#xe71e;</div>\n            <div class=\"fontclass\">.Hui-iconfont-huaxiayinxing</div>\n        </li>\n    \t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe704;</i>\n            <div class=\"name\">招商银行</div>\n            <div class=\"code\">&amp;#xe704;</div>\n            <div class=\"fontclass\">.Hui-iconfont-zhaoshangyinxing</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe723;</i>\n            <div class=\"name\">中信银行</div>\n            <div class=\"code\">&amp;#xe723;</div>\n            <div class=\"fontclass\">.Hui-iconfont-zhongxinyinxing</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe724;</i>\n            <div class=\"name\">上海银行</div>\n            <div class=\"code\">&amp;#xe724;</div>\n            <div class=\"fontclass\">.Hui-iconfont-shanghaiyinxing</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6ed;</i>\n            <div class=\"name\">温州银行</div>\n            <div class=\"code\">&amp;#xe6ed;</div>\n            <div class=\"fontclass\">.Hui-iconfont-wenzhouyinxing</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6f0;</i>\n            <div class=\"name\">光大银行</div>\n            <div class=\"code\">&amp;#xe6f0;</div>\n            <div class=\"fontclass\">.Hui-iconfont-guangdayinxing</div>\n        </li>\n    \n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6f4;</i>\n            <div class=\"name\">民生银行</div>\n            <div class=\"code\">&amp;#xe6f4;</div>\n            <div class=\"fontclass\">.Hui-iconfont-minshengyinxing</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6f6;</i>\n            <div class=\"name\">青岛银行</div>\n            <div class=\"code\">&amp;#xe6f6;</div>\n            <div class=\"fontclass\">.Hui-iconfont-qingdaoyinxing</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe6fb;</i>\n            <div class=\"name\">北京银行</div>\n            <div class=\"code\">&amp;#xe6fb;</div>\n            <div class=\"fontclass\">.Hui-iconfont-beijingyinxing</div>\n        </li>\n    \n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe703;</i>\n            <div class=\"name\">广东发展银行</div>\n            <div class=\"code\">&amp;#xe703;</div>\n            <div class=\"fontclass\">.Hui-iconfont-guangdongfazhanyinxing</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe712;</i>\n            <div class=\"name\">浙商银行</div>\n            <div class=\"code\">&amp;#xe712;</div>\n            <div class=\"fontclass\">.Hui-iconfont-zheshangyinxing</div>\n        </li> \n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe714;</i>\n            <div class=\"name\">成都银行</div>\n            <div class=\"code\">&amp;#xe714;</div>\n            <div class=\"fontclass\">.Hui-iconfont-cdbank</div>\n        </li>\n        <li>\n        \t<i class=\"icon Hui-iconfont\">&#xe718;</i>\n            <div class=\"name\">杭州银行</div>\n            <div class=\"code\">&amp;#xe718;</div>\n            <div class=\"fontclass\">.Hui-iconfont-hangzhouyinxing</div>\n        </li>\n\t</ul>\n\t<h2>其他</h2>\n\t<ul class=\"icon_lists cl\">\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6c7;</i>\n\t\t\t<div class=\"name\">电话</div>\n\t\t\t<div class=\"code\">&amp;#xe6c7;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tel</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6a3;</i>\n\t\t\t<div class=\"name\">电话</div>\n\t\t\t<div class=\"code\">&amp;#xe6a3;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-tel2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe696;</i>\n\t\t\t<div class=\"name\">iphone手机</div>\n\t\t\t<div class=\"code\">&amp;#xe696;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-phone</div>\n\t\t</li>\n\t\t<li>\n        \t<i class=\"icon Hui-iconfont\">&#xe708;</i>\n            <div class=\"name\">安卓手机</div>\n            <div class=\"code\">&amp;#xe708;</div>\n            <div class=\"fontclass\">.Hui-iconfont-phone-android</div>\n        </li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe64c;</i>\n\t\t\t<div class=\"name\">平板电脑</div>\n\t\t\t<div class=\"code\">&amp;#xe64c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-pad</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe64f;</i>\n\t\t\t<div class=\"name\">PC</div>\n\t\t\t<div class=\"code\">&amp;#xe64f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-xianshiqi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe650;</i>\n\t\t\t<div class=\"name\">照相机</div>\n\t\t\t<div class=\"code\">&amp;#xe650;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-zhaoxiangji</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe651;</i>\n\t\t\t<div class=\"name\">单反相机</div>\n\t\t\t<div class=\"code\">&amp;#xe651;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-danfanxiangji</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe652;</i>\n\t\t\t<div class=\"name\">打印机</div>\n\t\t\t<div class=\"code\">&amp;#xe652;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-dayinji</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe64d;</i>\n\t\t\t<div class=\"name\">轮胎</div>\n\t\t\t<div class=\"code\">&amp;#xe64d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-lunzi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe654;</i>\n\t\t\t<div class=\"name\">插件</div>\n\t\t\t<div class=\"code\">&amp;#xe654;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-chajian</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe655;</i>\n\t\t\t<div class=\"name\">节日</div>\n\t\t\t<div class=\"code\">&amp;#xe655;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-jieri</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe675;</i>\n\t\t\t<div class=\"name\">排序</div>\n\t\t\t<div class=\"code\">&amp;#xe675;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-paixu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe624;</i>\n\t\t\t<div class=\"name\">匿名</div>\n\t\t\t<div class=\"code\">&amp;#xe624;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-niming</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe62a;</i>\n\t\t\t<div class=\"name\">换肤</div>\n\t\t\t<div class=\"code\">&amp;#xe62a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-pifu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6cb;</i>\n\t\t\t<div class=\"name\">二维码</div>\n\t\t\t<div class=\"code\">&amp;#xe6cb;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-2code</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe682;</i>\n\t\t\t<div class=\"name\">扫一扫</div>\n\t\t\t<div class=\"code\">&amp;#xe682;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-saoyisao</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe683;</i>\n\t\t\t<div class=\"name\">搜索</div>\n\t\t\t<div class=\"code\">&amp;#xe683;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-search</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe68c;</i>\n\t\t\t<div class=\"name\">中图模式</div>\n\t\t\t<div class=\"code\">&amp;#xe68c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-zhongtumoshi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe68d;</i>\n\t\t\t<div class=\"name\">大图模式</div>\n\t\t\t<div class=\"code\">&amp;#xe68d;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-datumoshi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6be;</i>\n\t\t\t<div class=\"name\">大图模式</div>\n\t\t\t<div class=\"code\">&amp;#xe6be;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-bigpic</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6c0;</i>\n\t\t\t<div class=\"name\">中图模式</div>\n\t\t\t<div class=\"code\">&amp;#xe6c0;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-middle</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6bf;</i>\n\t\t\t<div class=\"name\">列表模式</div>\n\t\t\t<div class=\"code\">&amp;#xe6bf;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-list</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe690;</i>\n\t\t\t<div class=\"name\">时间</div>\n\t\t\t<div class=\"code\">&amp;#xe690;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-shijian</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe69c;</i>\n\t\t\t<div class=\"name\">更多</div>\n\t\t\t<div class=\"code\">&amp;#xe69c;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-more2</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe629;</i>\n\t\t\t<div class=\"name\">SIM卡</div>\n\t\t\t<div class=\"code\">&amp;#xe629;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-sim</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6c1;</i>\n\t\t\t<div class=\"name\">火热</div>\n\t\t\t<div class=\"code\">&amp;#xe6c1;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-hot</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6c2;</i>\n\t\t\t<div class=\"name\">拍摄</div>\n\t\t\t<div class=\"code\">&amp;#xe6c2;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-paishe</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6c3;</i>\n\t\t\t<div class=\"name\">热销</div>\n\t\t\t<div class=\"code\">&amp;#xe6c3;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-hot1</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6c4;</i>\n\t\t\t<div class=\"name\">上新</div>\n\t\t\t<div class=\"code\">&amp;#xe6c4;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-new</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6c6;</i>\n\t\t\t<div class=\"name\">产品参数</div>\n\t\t\t<div class=\"code\">&amp;#xe6c6;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-canshu</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6c9;</i>\n\t\t\t<div class=\"name\">定位</div>\n\t\t\t<div class=\"code\">&amp;#xe6c9;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-dingwei</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe671;</i>\n\t\t\t<div class=\"name\">定位</div>\n\t\t\t<div class=\"code\">&amp;#xe671;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-weizhi</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe69f;</i>\n\t\t\t<div class=\"name\">HTML</div>\n\t\t\t<div class=\"code\">&amp;#xe69f;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-html</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6a0;</i>\n\t\t\t<div class=\"name\">CSS</div>\n\t\t\t<div class=\"code\">&amp;#xe6a0;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-css</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe64a;</i>\n\t\t\t<div class=\"name\">苹果</div>\n\t\t\t<div class=\"code\">&amp;#xe64a;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-apple</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6a2;</i>\n\t\t\t<div class=\"name\">android</div>\n\t\t\t<div class=\"code\">&amp;#xe6a2;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-android</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6d1;</i>\n\t\t\t<div class=\"name\">github</div>\n\t\t\t<div class=\"code\">&amp;#xe6d1;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-github</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6d2;</i>\n\t\t\t<div class=\"name\">html5</div>\n\t\t\t<div class=\"code\">&amp;#xe6d2;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-html5</div>\n\t\t</li>\n\t\t<li> <i class=\"icon Hui-iconfont\">&#xe6d3;</i>\n\t\t\t<div class=\"name\">皇冠</div>\n\t\t\t<div class=\"code\">&amp;#xe6d3;</div>\n\t\t\t<div class=\"fontclass\">.Hui-iconfont-huangguan</div>\n\t\t</li>\n\t</ul>\n\t<div class=\"helps\">\n\t\t<p>挑选相应图标并获取字体编码，应用于页面</p>\n\t\t<pre>&lt;i class=\"Hui-iconfont\"&gt;&amp;#xe684;&lt;/i&gt;</pre>\n\t</div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "public/static/lib/Hui-iconfont/1.0.8/iconfont.css",
    "content": "/* -----------H-ui前端框架-------------\n* iconfont.css v1.0.8\n* http://www.h-ui.net/\n* Created & Modified by guojunhui\n* Date modified 2016.06.21\n*\n* Copyright 2013-2015 北京颖杰联创科技有限公司 All rights reserved.\n* Licensed under MIT license.\n* http://opensource.org/licenses/MIT\n*\n*/\n@font-face {font-family: \"Hui-iconfont\";\n  src: url('iconfont.eot'); /* IE9*/\n  src: url('iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */\n  url('iconfont.woff') format('woff'), /* chrome、firefox */\n  url('iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/\n  url('iconfont.svg#Hui-iconfont') format('svg'); /* iOS 4.1- */\n}\n\n.Hui-iconfont {\n  font-family:\"Hui-iconfont\" !important;\n  font-style:normal;\n  -webkit-font-smoothing: antialiased;\n  -webkit-text-stroke-width: 0.2px;\n  -moz-osx-font-smoothing: grayscale;\n}\n.Hui-iconfont-gotop:before { content: \"\\e684\"; }\n.Hui-iconfont-music:before { content: \"\\e60f\"; }\n.Hui-iconfont-tags:before { content: \"\\e64b\"; }\n.Hui-iconfont-jieri:before { content: \"\\e727\"; }\n.Hui-iconfont-jishiqi:before { content: \"\\e728\"; }\n.Hui-iconfont-pad:before { content: \"\\e64c\"; }\n.Hui-iconfont-lunzi:before { content: \"\\e64d\"; }\n.Hui-iconfont-jiandao:before { content: \"\\e64e\"; }\n.Hui-iconfont-xianshiqi:before { content: \"\\e64f\"; }\n.Hui-iconfont-zhaoxiangji:before { content: \"\\e650\"; }\n.Hui-iconfont-danfanxiangji:before { content: \"\\e651\"; }\n.Hui-iconfont-dayinji:before { content: \"\\e652\"; }\n.Hui-iconfont-user-zhanzhang:before { content: \"\\e653\"; }\n.Hui-iconfont-chajian:before { content: \"\\e654\"; }\n.Hui-iconfont-arrow1-bottom:before { content: \"\\e674\"; }\n.Hui-iconfont-arrow1-left:before { content: \"\\e678\"; }\n.Hui-iconfont-arrow1-top:before { content: \"\\e679\"; }\n.Hui-iconfont-arrow1-right:before { content: \"\\e67a\"; }\n.Hui-iconfont-jieri1:before { content: \"\\e655\"; }\n.Hui-iconfont-face-weixiao:before { content: \"\\e656\"; }\n.Hui-iconfont-face-chijing:before { content: \"\\e657\"; }\n.Hui-iconfont-face-dai:before { content: \"\\e658\"; }\n.Hui-iconfont-face-shuaku:before { content: \"\\e659\"; }\n.Hui-iconfont-face-mogui:before { content: \"\\e65a\"; }\n.Hui-iconfont-face-ganga:before { content: \"\\e65b\"; }\n.Hui-iconfont-face-qin:before { content: \"\\e65c\"; }\n.Hui-iconfont-face-nu:before { content: \"\\e65d\"; }\n.Hui-iconfont-face-zhayan:before { content: \"\\e65e\"; }\n.Hui-iconfont-face-shengqi:before { content: \"\\e65f\"; }\n.Hui-iconfont-face-ma:before { content: \"\\e660\"; }\n.Hui-iconfont-face-bishi:before { content: \"\\e661\"; }\n.Hui-iconfont-face-maimeng:before { content: \"\\e662\"; }\n.Hui-iconfont-face-jingdai:before { content: \"\\e663\"; }\n.Hui-iconfont-face-yun:before { content: \"\\e664\"; }\n.Hui-iconfont-home2:before { content: \"\\e67f\"; }\n.Hui-iconfont-search2:before { content: \"\\e665\"; }\n.Hui-iconfont-share2:before { content: \"\\e666\"; }\n.Hui-iconfont-face:before { content: \"\\e668\"; }\n.Hui-iconfont-wuliu:before { content: \"\\e669\"; }\n.Hui-iconfont-dianpu:before { content: \"\\e66a\"; }\n.Hui-iconfont-chexiao:before { content: \"\\e66b\"; }\n.Hui-iconfont-zhongzuo:before { content: \"\\e66c\"; }\n.Hui-iconfont-zan:before { content: \"\\e66d\"; }\n.Hui-iconfont-cai:before { content: \"\\e66e\"; }\n.Hui-iconfont-yuyin3:before { content: \"\\e66f\"; }\n.Hui-iconfont-cart2-selected:before { content: \"\\e670\"; }\n.Hui-iconfont-weizhi:before { content: \"\\e671\"; }\n.Hui-iconfont-face-ku:before { content: \"\\e688\"; }\n.Hui-iconfont-down:before { content: \"\\e640\"; }\n.Hui-iconfont-cart2-man:before { content: \"\\e672\"; }\n.Hui-iconfont-card2-kong:before { content: \"\\e673\"; }\n.Hui-iconfont-luyin:before { content: \"\\e619\"; }\n.Hui-iconfont-html:before { content: \"\\e69f\"; }\n.Hui-iconfont-css:before { content: \"\\e6a0\"; }\n.Hui-iconfont-android:before { content: \"\\e6a2\"; }\n.Hui-iconfont-github:before { content: \"\\e6d1\"; }\n.Hui-iconfont-html5:before { content: \"\\e6d2\"; }\n.Hui-iconfont-huangguan:before { content: \"\\e6d3\"; }\n.Hui-iconfont-news:before { content: \"\\e616\"; }\n.Hui-iconfont-slider-right:before { content: \"\\e63d\"; }\n.Hui-iconfont-slider-left:before { content: \"\\e67d\"; }\n.Hui-iconfont-tuku:before { content: \"\\e613\"; }\n.Hui-iconfont-shuru:before { content: \"\\e647\"; }\n.Hui-iconfont-sanjiao:before { content: \"\\e67e\"; }\n.Hui-iconfont-share-renren:before { content: \"\\e6d8\"; }\n.Hui-iconfont-share-tweibo:before { content: \"\\e6d9\"; }\n.Hui-iconfont-arrow2-left:before { content: \"\\e6d4\"; }\n.Hui-iconfont-paixu:before { content: \"\\e675\"; }\n.Hui-iconfont-niming:before { content: \"\\e624\"; }\n.Hui-iconfont-add:before { content: \"\\e600\"; }\n.Hui-iconfont-root:before { content: \"\\e62d\"; }\n.Hui-iconfont-xuanzhong:before { content: \"\\e676\"; }\n.Hui-iconfont-weixuanzhong:before { content: \"\\e677\"; }\n.Hui-iconfont-arrow2-bottom:before { content: \"\\e6d5\"; }\n.Hui-iconfont-arrow2-top:before { content: \"\\e6d6\"; }\n.Hui-iconfont-like2:before { content: \"\\e648\"; }\n.Hui-iconfont-arrow2-right:before { content: \"\\e6d7\"; }\n.Hui-iconfont-shangyishou:before { content: \"\\e6db\"; }\n.Hui-iconfont-xiayishou:before { content: \"\\e6e3\"; }\n.Hui-iconfont-share-weixin:before { content: \"\\e694\"; }\n.Hui-iconfont-shenhe-tingyong:before { content: \"\\e631\"; }\n.Hui-iconfont-gouxuan2:before { content: \"\\e601\"; }\n.Hui-iconfont-selected:before { content: \"\\e617\"; }\n.Hui-iconfont-jianhao:before { content: \"\\e6a1\"; }\n.Hui-iconfont-user-group:before { content: \"\\e62b\"; }\n.Hui-iconfont-yiguanzhu:before { content: \"\\e680\"; }\n.Hui-iconfont-gengduo3:before { content: \"\\e6f9\"; }\n.Hui-iconfont-comment:before { content: \"\\e622\"; }\n.Hui-iconfont-tongji-zhu:before { content: \"\\e618\"; }\n.Hui-iconfont-like:before { content: \"\\e649\"; }\n.Hui-iconfont-shangjia:before { content: \"\\e6dc\"; }\n.Hui-iconfont-save:before { content: \"\\e632\"; }\n.Hui-iconfont-gongsi:before { content: \"\\e643\"; }\n.Hui-iconfont-system:before { content: \"\\e62e\"; }\n.Hui-iconfont-pifu:before { content: \"\\e62a\"; }\n.Hui-iconfont-menu:before { content: \"\\e667\"; }\n.Hui-iconfont-msg:before { content: \"\\e62f\"; }\n.Hui-iconfont-huangguan1:before { content: \"\\e729\"; }\n.Hui-iconfont-userid:before { content: \"\\e602\"; }\n.Hui-iconfont-cang-selected:before { content: \"\\e630\"; }\n.Hui-iconfont-yundown:before { content: \"\\e641\"; }\n.Hui-iconfont-help:before { content: \"\\e633\"; }\n.Hui-iconfont-chuku:before { content: \"\\e634\"; }\n.Hui-iconfont-picture:before { content: \"\\e646\"; }\n.Hui-iconfont-wenzhouyinxing:before { content: \"\\e6ed\"; }\n.Hui-iconfont-ad:before { content: \"\\e635\"; }\n.Hui-iconfont-fenlei:before { content: \"\\e681\"; }\n.Hui-iconfont-saoyisao:before { content: \"\\e682\"; }\n.Hui-iconfont-search:before { content: \"\\e683\"; }\n.Hui-iconfont-tuwenxiangqing:before { content: \"\\e685\"; }\n.Hui-iconfont-leijipingjia:before { content: \"\\e686\"; }\n.Hui-iconfont-hetong:before { content: \"\\e636\"; }\n.Hui-iconfont-tongji:before { content: \"\\e61a\"; }\n.Hui-iconfont-quanbudingdan:before { content: \"\\e687\"; }\n.Hui-iconfont-cang:before { content: \"\\e61b\"; }\n.Hui-iconfont-xiaoxi:before { content: \"\\e68a\"; }\n.Hui-iconfont-renwu:before { content: \"\\e637\"; }\n.Hui-iconfont-more:before { content: \"\\e68b\"; }\n.Hui-iconfont-zhizhao:before { content: \"\\e638\"; }\n.Hui-iconfont-fabu:before { content: \"\\e603\"; }\n.Hui-iconfont-shenhe-butongguo2:before { content: \"\\e6dd\"; }\n.Hui-iconfont-share-qq:before { content: \"\\e67b\"; }\n.Hui-iconfont-upload:before { content: \"\\e642\"; }\n.Hui-iconfont-add2:before { content: \"\\e604\"; }\n.Hui-iconfont-jiesuo:before { content: \"\\e605\"; }\n.Hui-iconfont-zhongtumoshi:before { content: \"\\e68c\"; }\n.Hui-iconfont-datumoshi:before { content: \"\\e68d\"; }\n.Hui-iconfont-face2:before { content: \"\\e68e\"; }\n.Hui-iconfont-huanyipi:before { content: \"\\e68f\"; }\n.Hui-iconfont-shijian:before { content: \"\\e690\"; }\n.Hui-iconfont-feedback:before { content: \"\\e691\"; }\n.Hui-iconfont-feedback2:before { content: \"\\e692\"; }\n.Hui-iconfont-share-pengyouquan:before { content: \"\\e693\"; }\n.Hui-iconfont-zan2:before { content: \"\\e697\"; }\n.Hui-iconfont-arrow3-bottom:before { content: \"\\e698\"; }\n.Hui-iconfont-arrow3-top:before { content: \"\\e699\"; }\n.Hui-iconfont-arrow3-right:before { content: \"\\e69a\"; }\n.Hui-iconfont-arrow3-left:before { content: \"\\e69b\"; }\n.Hui-iconfont-more2:before { content: \"\\e69c\"; }\n.Hui-iconfont-cang2-selected:before { content: \"\\e69d\"; }\n.Hui-iconfont-cang2:before { content: \"\\e69e\"; }\n.Hui-iconfont-dangan:before { content: \"\\e639\"; }\n.Hui-iconfont-money:before { content: \"\\e63a\"; }\n.Hui-iconfont-share-weibo:before { content: \"\\e6da\"; }\n.Hui-iconfont-email:before { content: \"\\e63b\"; }\n.Hui-iconfont-tongji-xian:before { content: \"\\e61c\"; }\n.Hui-iconfont-bank:before { content: \"\\e628\"; }\n.Hui-iconfont-home:before { content: \"\\e625\"; }\n.Hui-iconfont-user:before { content: \"\\e62c\"; }\n.Hui-iconfont-log:before { content: \"\\e623\"; }\n.Hui-iconfont-pages:before { content: \"\\e626\"; }\n.Hui-iconfont-sim:before { content: \"\\e629\"; }\n.Hui-iconfont-tingzhi:before { content: \"\\e6e4\"; }\n.Hui-iconfont-dengdai:before { content: \"\\e606\"; }\n.Hui-iconfont-user-add:before { content: \"\\e607\"; }\n.Hui-iconfont-copy:before { content: \"\\e6ea\"; }\n.Hui-iconfont-file:before { content: \"\\e63e\"; }\n.Hui-iconfont-share-douban:before { content: \"\\e67c\"; }\n.Hui-iconfont-share-zhihu:before { content: \"\\e689\"; }\n.Hui-iconfont-daochu:before { content: \"\\e644\"; }\n.Hui-iconfont-daoru:before { content: \"\\e645\"; }\n.Hui-iconfont-weigouxuan2:before { content: \"\\e608\"; }\n.Hui-iconfont-phone:before { content: \"\\e696\"; }\n.Hui-iconfont-bold:before { content: \"\\e6e7\"; }\n.Hui-iconfont-manage2:before { content: \"\\e63c\"; }\n.Hui-iconfont-edit:before { content: \"\\e6df\"; }\n.Hui-iconfont-del2:before { content: \"\\e609\"; }\n.Hui-iconfont-duigou:before { content: \"\\e6e8\"; }\n.Hui-iconfont-chongqi:before { content: \"\\e6f7\"; }\n.Hui-iconfont-avatar:before { content: \"\\e60a\"; }\n.Hui-iconfont-del:before { content: \"\\e60b\"; }\n.Hui-iconfont-edit2:before { content: \"\\e60c\"; }\n.Hui-iconfont-zanting:before { content: \"\\e6e5\"; }\n.Hui-iconfont-apple:before { content: \"\\e64a\"; }\n.Hui-iconfont-guangdayinxing:before { content: \"\\e6f0\"; }\n.Hui-iconfont-minshengyinxing:before { content: \"\\e6f4\"; }\n.Hui-iconfont-xiajia:before { content: \"\\e6de\"; }\n.Hui-iconfont-manage:before { content: \"\\e61d\"; }\n.Hui-iconfont-user2:before { content: \"\\e60d\"; }\n.Hui-iconfont-code:before { content: \"\\e6ee\"; }\n.Hui-iconfont-cut:before { content: \"\\e6ef\"; }\n.Hui-iconfont-link:before { content: \"\\e6f1\"; }\n.Hui-iconfont-new:before { content: \"\\e6f2\"; }\n.Hui-iconfont-ordered-list:before { content: \"\\e6f3\"; }\n.Hui-iconfont-unordered-list:before { content: \"\\e6f5\"; }\n.Hui-iconfont-share-qzone:before { content: \"\\e6c8\"; }\n.Hui-iconfont-suoding:before { content: \"\\e60e\"; }\n.Hui-iconfont-tel2:before { content: \"\\e6a3\"; }\n.Hui-iconfont-order:before { content: \"\\e627\"; }\n.Hui-iconfont-shujutongji:before { content: \"\\e61e\"; }\n.Hui-iconfont-del3:before { content: \"\\e6e2\"; }\n.Hui-iconfont-add3:before { content: \"\\e610\"; }\n.Hui-iconfont-add4:before { content: \"\\e61f\"; }\n.Hui-iconfont-xiangpicha:before { content: \"\\e72a\"; }\n.Hui-iconfont-key:before { content: \"\\e63f\"; }\n.Hui-iconfont-yuyin2:before { content: \"\\e6a4\"; }\n.Hui-iconfont-yuyin:before { content: \"\\e6a5\"; }\n.Hui-iconfont-close:before { content: \"\\e6a6\"; }\n.Hui-iconfont-xuanze:before { content: \"\\e6a7\"; }\n.Hui-iconfont-xuanzhong1:before { content: \"\\e6a8\"; }\n.Hui-iconfont-yiguanzhu1:before { content: \"\\e6a9\"; }\n.Hui-iconfont-share:before { content: \"\\e6aa\"; }\n.Hui-iconfont-zhuanfa:before { content: \"\\e6ab\"; }\n.Hui-iconfont-tianqi-duoyun:before { content: \"\\e6ac\"; }\n.Hui-iconfont-tianqi-mai:before { content: \"\\e6ad\"; }\n.Hui-iconfont-tianqi-qing:before { content: \"\\e6ae\"; }\n.Hui-iconfont-tianqi-wu:before { content: \"\\e6af\"; }\n.Hui-iconfont-tianqi-xue:before { content: \"\\e6b0\"; }\n.Hui-iconfont-tianqi-yin:before { content: \"\\e6b1\"; }\n.Hui-iconfont-tianqi-yu:before { content: \"\\e6b2\"; }\n.Hui-iconfont-daipingjia:before { content: \"\\e6b3\"; }\n.Hui-iconfont-vip-card2:before { content: \"\\e6b4\"; }\n.Hui-iconfont-jifen:before { content: \"\\e6b5\"; }\n.Hui-iconfont-youhuiquan:before { content: \"\\e6b6\"; }\n.Hui-iconfont-hongbao:before { content: \"\\e6b7\"; }\n.Hui-iconfont-cart-selected:before { content: \"\\e6b8\"; }\n.Hui-iconfont-cart-kong:before { content: \"\\e6b9\"; }\n.Hui-iconfont-jiangjia:before { content: \"\\e6ba\"; }\n.Hui-iconfont-liwu:before { content: \"\\e6bb\"; }\n.Hui-iconfont-caiqie:before { content: \"\\e6bc\"; }\n.Hui-iconfont-xuanzhuan:before { content: \"\\e6bd\"; }\n.Hui-iconfont-bigpic:before { content: \"\\e6be\"; }\n.Hui-iconfont-list:before { content: \"\\e6bf\"; }\n.Hui-iconfont-middle:before { content: \"\\e6c0\"; }\n.Hui-iconfont-hot:before { content: \"\\e6c1\"; }\n.Hui-iconfont-paishe:before { content: \"\\e6c2\"; }\n.Hui-iconfont-hot1:before { content: \"\\e6c3\"; }\n.Hui-iconfont-new1:before { content: \"\\e6c4\"; }\n.Hui-iconfont-xiaoxi1:before { content: \"\\e6c5\"; }\n.Hui-iconfont-canshu:before { content: \"\\e6c6\"; }\n.Hui-iconfont-tel:before { content: \"\\e6c7\"; }\n.Hui-iconfont-dingwei:before { content: \"\\e6c9\"; }\n.Hui-iconfont-hongbao2:before { content: \"\\e6ca\"; }\n.Hui-iconfont-2code:before { content: \"\\e6cb\"; }\n.Hui-iconfont-vip:before { content: \"\\e6cc\"; }\n.Hui-iconfont-tishi:before { content: \"\\e6cd\"; }\n.Hui-iconfont-dingyue:before { content: \"\\e6ce\"; }\n.Hui-iconfont-italic:before { content: \"\\e6e9\"; }\n.Hui-iconfont-yulan:before { content: \"\\e695\"; }\n.Hui-iconfont-usergroup2:before { content: \"\\e611\"; }\n.Hui-iconfont-goods:before { content: \"\\e620\"; }\n.Hui-iconfont-paixingbang:before { content: \"\\e6cf\"; }\n.Hui-iconfont-qingdaoyinxing:before { content: \"\\e6f6\"; }\n.Hui-iconfont-kefu:before { content: \"\\e6d0\"; }\n.Hui-iconfont-picture1:before { content: \"\\e612\"; }\n.Hui-iconfont-weigouxuan:before { content: \"\\e614\"; }\n.Hui-iconfont-fanqiang:before { content: \"\\e6fa\"; }\n.Hui-iconfont-shenhe-weitongguo:before { content: \"\\e6e0\"; }\n.Hui-iconfont-shenhe-tongguo:before { content: \"\\e6e1\"; }\n.Hui-iconfont-tongji-bing:before { content: \"\\e621\"; }\n.Hui-iconfont-gouxuan:before { content: \"\\e615\"; }\n.Hui-iconfont-jiansheyinxing:before { content: \"\\e6f8\"; }\n.Hui-iconfont-moban:before { content: \"\\e72b\"; }\n.Hui-iconfont-pay-weixin:before { content: \"\\e719\"; }\n.Hui-iconfont-pay-alipay-2:before { content: \"\\e71c\"; }\n.Hui-iconfont-beijingyinxing:before { content: \"\\e6fb\"; }\n.Hui-iconfont-guangdongfazhanyinxing:before { content: \"\\e703\"; }\n.Hui-iconfont-zhaoshangyinxing:before { content: \"\\e704\"; }\n.Hui-iconfont-zheshangyinxing:before { content: \"\\e712\"; }\n.Hui-iconfont-zhongguonongyeyinxing:before { content: \"\\e713\"; }\n.Hui-iconfont-cdbank:before { content: \"\\e714\"; }\n.Hui-iconfont-gengduo2:before { content: \"\\e716\"; }\n.Hui-iconfont-bofang:before { content: \"\\e6e6\"; }\n.Hui-iconfont-gengduo4:before { content: \"\\e717\"; }\n.Hui-iconfont-text-height:before { content: \"\\e6fc\"; }\n.Hui-iconfont-text-width:before { content: \"\\e6fd\"; }\n.Hui-iconfont-underline:before { content: \"\\e6fe\"; }\n.Hui-iconfont-star:before { content: \"\\e6ff\"; }\n.Hui-iconfont-star-half:before { content: \"\\e700\"; }\n.Hui-iconfont-star-halfempty:before { content: \"\\e701\"; }\n.Hui-iconfont-star-o:before { content: \"\\e702\"; }\n.Hui-iconfont-font:before { content: \"\\e6ec\"; }\n.Hui-iconfont-hangzhouyinxing:before { content: \"\\e718\"; }\n.Hui-iconfont-jiaotongyinxing:before { content: \"\\e71a\"; }\n.Hui-iconfont-gengduo:before { content: \"\\e715\"; }\n.Hui-iconfont-avatar2:before { content: \"\\e705\"; }\n.Hui-iconfont-close2:before { content: \"\\e706\"; }\n.Hui-iconfont-about:before { content: \"\\e707\"; }\n.Hui-iconfont-phone-android:before { content: \"\\e708\"; }\n.Hui-iconfont-search1:before { content: \"\\e709\"; }\n.Hui-iconfont-comment1:before { content: \"\\e70a\"; }\n.Hui-iconfont-read:before { content: \"\\e70b\"; }\n.Hui-iconfont-feedback1:before { content: \"\\e70c\"; }\n.Hui-iconfont-practice:before { content: \"\\e70d\"; }\n.Hui-iconfont-align-center:before { content: \"\\e70e\"; }\n.Hui-iconfont-align-justify:before { content: \"\\e70f\"; }\n.Hui-iconfont-align-left:before { content: \"\\e710\"; }\n.Hui-iconfont-align-right:before { content: \"\\e711\"; }\n.Hui-iconfont-paste:before { content: \"\\e6eb\"; }\n.Hui-iconfont-pay-alipay-1:before { content: \"\\e71f\"; }\n.Hui-iconfont-pufayinxing:before { content: \"\\e71b\"; }\n.Hui-iconfont-gongshangyinxing:before { content: \"\\e71d\"; }\n.Hui-iconfont-huaxiayinxing:before { content: \"\\e71e\"; }\n.Hui-iconfont-youzhengyinxing:before { content: \"\\e721\"; }\n.Hui-iconfont-zhongguoyinxing:before { content: \"\\e722\"; }\n.Hui-iconfont-zhongxinyinxing:before { content: \"\\e723\"; }\n.Hui-iconfont-shanghaiyinxing:before { content: \"\\e724\"; }\n.Hui-iconfont-banzhu:before { content: \"\\e72c\"; }\n.Hui-iconfont-yuedu:before { content: \"\\e720\"; }\n.Hui-iconfont-yanjing:before { content: \"\\e725\"; }\n.Hui-iconfont-power:before { content: \"\\e726\"; }\n.Hui-iconfont-moban-2:before { content: \"\\e72d\"; }\n"
  },
  {
    "path": "public/static/lib/html5shiv.js",
    "content": "/*\n HTML5 Shiv v3.7.0 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed\n*/\n(function(l,f){function m(){var a=e.elements;return\"string\"==typeof a?a.split(\" \"):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();\na.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function(\"h,f\",\"return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&(\"+m().join().replace(/[\\w\\-]+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c(\"'+a+'\")'})+\");return n}\")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement(\"p\");d=d.getElementsByTagName(\"head\")[0]||d.documentElement;c.innerHTML=\"x<style>article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}</style>\";\nc=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o=\"_html5shiv\",h=0,n={},g;(function(){try{var a=f.createElement(\"a\");a.innerHTML=\"<xyz></xyz>\";j=\"hidden\"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement(\"a\");var c=f.createDocumentFragment();b=\"undefined\"==typeof c.cloneNode||\n\"undefined\"==typeof c.createDocumentFragment||\"undefined\"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||\"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video\",version:\"3.7.0\",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:\"default\",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);\nif(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);\n"
  },
  {
    "path": "public/static/lib/jquery/1.9.1/jquery.js",
    "content": "/*!\n * jQuery JavaScript Library v1.9.1\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2013-2-4\n */\n(function( window, undefined ) {\n\n// Can't do this because several apps 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// Support: Firefox 18+\n//\"use strict\";\nvar\n\t// The deferred used on DOM ready\n\treadyList,\n\n\t// A central reference to the root jQuery(document)\n\trootjQuery,\n\n\t// Support: IE<9\n\t// For `typeof node.method` instead of `node.method !== undefined`\n\tcore_strundefined = typeof undefined,\n\n\t// Use the correct document accordingly with window argument (sandbox)\n\tdocument = window.document,\n\tlocation = window.location,\n\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\n\t// [[Class]] -> type pairs\n\tclass2type = {},\n\n\t// List of deleted data cache ids, so we can reuse them\n\tcore_deletedIds = [],\n\n\tcore_version = \"1.9.1\",\n\n\t// Save a reference to some core methods\n\tcore_concat = core_deletedIds.concat,\n\tcore_push = core_deletedIds.push,\n\tcore_slice = core_deletedIds.slice,\n\tcore_indexOf = core_deletedIds.indexOf,\n\tcore_toString = class2type.toString,\n\tcore_hasOwn = class2type.hasOwnProperty,\n\tcore_trim = core_version.trim,\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\treturn new jQuery.fn.init( selector, context, rootjQuery );\n\t},\n\n\t// Used for matching numbers\n\tcore_pnum = /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,\n\n\t// Used for splitting on whitespace\n\tcore_rnotwhite = /\\S+/g,\n\n\t// Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\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 = /^(?:(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,\n\n\t// Match a standalone tag\n\trsingleTag = /^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/,\n\n\t// JSON RegExp\n\trvalidchars = /^[\\],:{}\\s]*$/,\n\trvalidbraces = /(?:^|:|,)(?:\\s*\\[)+/g,\n\trvalidescape = /\\\\(?:[\"\\\\\\/bfnrt]|u[\\da-fA-F]{4})/g,\n\trvalidtokens = /\"[^\"\\\\\\r\\n]*\"|true|false|null|-?(?:\\d+\\.|)\\d+(?:[eE][+-]?\\d+|)/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\n\t// The ready event handler\n\tcompleted = function( event ) {\n\n\t\t// readyState === \"complete\" is good enough for us to call the dom ready in oldIE\n\t\tif ( document.addEventListener || event.type === \"load\" || document.readyState === \"complete\" ) {\n\t\t\tdetach();\n\t\t\tjQuery.ready();\n\t\t}\n\t},\n\t// Clean-up method for dom ready events\n\tdetach = function() {\n\t\tif ( document.addEventListener ) {\n\t\t\tdocument.removeEventListener( \"DOMContentLoaded\", completed, false );\n\t\t\twindow.removeEventListener( \"load\", completed, false );\n\n\t\t} else {\n\t\t\tdocument.detachEvent( \"onreadystatechange\", completed );\n\t\t\twindow.detachEvent( \"onload\", completed );\n\t\t}\n\t};\n\njQuery.fn = jQuery.prototype = {\n\t// The current version of jQuery being used\n\tjquery: core_version,\n\n\tconstructor: jQuery,\n\tinit: function( selector, context, rootjQuery ) {\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.charAt(0) === \"<\" && selector.charAt( 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// scripts is true for back-compat\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// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE and Opera return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id !== match[2] ) {\n\t\t\t\t\t\t\treturn rootjQuery.find( selector );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Otherwise, we 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 rootjQuery.ready( selector );\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\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\t// The number of elements contained in the matched element set\n\tsize: function() {\n\t\treturn this.length;\n\t},\n\n\ttoArray: function() {\n\t\treturn core_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 a 'clean' array\n\t\t\tthis.toArray() :\n\n\t\t\t// Return just the object\n\t\t\t( num < 0 ? this[ this.length + num ] : this[ num ] );\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\tready: function( fn ) {\n\t\t// Add the callback\n\t\tjQuery.ready.promise().done( fn );\n\n\t\treturn this;\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( core_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\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\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: core_push,\n\tsort: [].sort,\n\tsplice: [].splice\n};\n\n// Give the init function the jQuery prototype for later instantiation\njQuery.fn.init.prototype = jQuery.fn;\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar src, copyIsArray, copy, name, options, 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\t\ttarget = arguments[1] || {};\n\t\t// skip the boolean and the target\n\t\ti = 2;\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 ( length === i ) {\n\t\ttarget = this;\n\t\t--i;\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\tnoConflict: function( deep ) {\n\t\tif ( window.$ === jQuery ) {\n\t\t\twindow.$ = _$;\n\t\t}\n\n\t\tif ( deep && window.jQuery === jQuery ) {\n\t\t\twindow.jQuery = _jQuery;\n\t\t}\n\n\t\treturn jQuery;\n\t},\n\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// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n\t\tif ( !document.body ) {\n\t\t\treturn setTimeout( jQuery.ready );\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.trigger ) {\n\t\t\tjQuery( document ).trigger(\"ready\").off(\"ready\");\n\t\t}\n\t},\n\n\t// See test/unit/core.js for details concerning isFunction.\n\t// Since version 1.3, DOM methods and functions like alert\n\t// aren't supported. They return false on IE (#2968).\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type(obj) === \"function\";\n\t},\n\n\tisArray: Array.isArray || function( obj ) {\n\t\treturn jQuery.type(obj) === \"array\";\n\t},\n\n\tisWindow: function( obj ) {\n\t\treturn obj != null && obj == obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\t\treturn !isNaN( parseFloat(obj) ) && isFinite( obj );\n\t},\n\n\ttype: function( obj ) {\n\t\tif ( obj == null ) {\n\t\t\treturn String( obj );\n\t\t}\n\t\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\t\tclass2type[ core_toString.call(obj) ] || \"object\" :\n\t\t\ttypeof obj;\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\t// Must be an Object.\n\t\t// Because of IE, we also have to check the presence of the constructor property.\n\t\t// Make sure that DOM nodes and window objects don't pass through, as well\n\t\tif ( !obj || jQuery.type(obj) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\t// Not own constructor property must be Object\n\t\t\tif ( obj.constructor &&\n\t\t\t\t!core_hasOwn.call(obj, \"constructor\") &&\n\t\t\t\t!core_hasOwn.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\t// IE8,9 Will throw exceptions on certain host objects #9897\n\t\t\treturn false;\n\t\t}\n\n\t\t// Own properties are enumerated firstly, so to speed up,\n\t\t// if last one is own, then all properties are own.\n\n\t\tvar key;\n\t\tfor ( key in obj ) {}\n\n\t\treturn key === undefined || core_hasOwn.call( obj, key );\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\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\t// data: string of html\n\t// context (optional): If specified, the fragment will be created in this context, defaults to document\n\t// keepScripts (optional): If true, will include scripts passed in the html string\n\tparseHTML: function( data, context, keepScripts ) {\n\t\tif ( !data || typeof data !== \"string\" ) {\n\t\t\treturn null;\n\t\t}\n\t\tif ( typeof context === \"boolean\" ) {\n\t\t\tkeepScripts = context;\n\t\t\tcontext = false;\n\t\t}\n\t\tcontext = context || document;\n\n\t\tvar parsed = rsingleTag.exec( data ),\n\t\t\tscripts = !keepScripts && [];\n\n\t\t// Single tag\n\t\tif ( parsed ) {\n\t\t\treturn [ context.createElement( parsed[1] ) ];\n\t\t}\n\n\t\tparsed = jQuery.buildFragment( [ data ], context, scripts );\n\t\tif ( scripts ) {\n\t\t\tjQuery( scripts ).remove();\n\t\t}\n\t\treturn jQuery.merge( [], parsed.childNodes );\n\t},\n\n\tparseJSON: function( data ) {\n\t\t// Attempt to parse using the native JSON parser first\n\t\tif ( window.JSON && window.JSON.parse ) {\n\t\t\treturn window.JSON.parse( data );\n\t\t}\n\n\t\tif ( data === null ) {\n\t\t\treturn data;\n\t\t}\n\n\t\tif ( typeof data === \"string\" ) {\n\n\t\t\t// Make sure leading/trailing whitespace is removed (IE can't handle it)\n\t\t\tdata = jQuery.trim( data );\n\n\t\t\tif ( data ) {\n\t\t\t\t// Make sure the incoming data is actual JSON\n\t\t\t\t// Logic borrowed from http://json.org/json2.js\n\t\t\t\tif ( rvalidchars.test( data.replace( rvalidescape, \"@\" )\n\t\t\t\t\t.replace( rvalidtokens, \"]\" )\n\t\t\t\t\t.replace( rvalidbraces, \"\")) ) {\n\n\t\t\t\t\treturn ( new Function( \"return \" + data ) )();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tjQuery.error( \"Invalid JSON: \" + data );\n\t},\n\n\t// Cross-browser xml parsing\n\tparseXML: function( data ) {\n\t\tvar xml, tmp;\n\t\tif ( !data || typeof data !== \"string\" ) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tif ( window.DOMParser ) { // Standard\n\t\t\t\ttmp = new DOMParser();\n\t\t\t\txml = tmp.parseFromString( data , \"text/xml\" );\n\t\t\t} else { // IE\n\t\t\t\txml = new ActiveXObject( \"Microsoft.XMLDOM\" );\n\t\t\t\txml.async = \"false\";\n\t\t\t\txml.loadXML( data );\n\t\t\t}\n\t\t} catch( e ) {\n\t\t\txml = undefined;\n\t\t}\n\t\tif ( !xml || !xml.documentElement || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\t\tjQuery.error( \"Invalid XML: \" + data );\n\t\t}\n\t\treturn xml;\n\t},\n\n\tnoop: function() {},\n\n\t// Evaluates a script in a global context\n\t// Workarounds based on findings by Jim Driscoll\n\t// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context\n\tglobalEval: function( data ) {\n\t\tif ( data && jQuery.trim( data ) ) {\n\t\t\t// We use execScript on Internet Explorer\n\t\t\t// We use an anonymous function so that context is window\n\t\t\t// rather than jQuery in Firefox\n\t\t\t( window.execScript || function( data ) {\n\t\t\t\twindow[ \"eval\" ].call( window, data );\n\t\t\t} )( data );\n\t\t}\n\t},\n\n\t// Convert dashed to camelCase; used by the css and data modules\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// Use native String.trim function wherever possible\n\ttrim: core_trim && !core_trim.call(\"\\uFEFF\\xA0\") ?\n\t\tfunction( text ) {\n\t\t\treturn text == null ?\n\t\t\t\t\"\" :\n\t\t\t\tcore_trim.call( text );\n\t\t} :\n\n\t\t// Otherwise use our own trimming functionality\n\t\tfunction( text ) {\n\t\t\treturn text == null ?\n\t\t\t\t\"\" :\n\t\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t\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\tcore_push.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\tvar len;\n\n\t\tif ( arr ) {\n\t\t\tif ( core_indexOf ) {\n\t\t\t\treturn core_indexOf.call( arr, elem, i );\n\t\t\t}\n\n\t\t\tlen = arr.length;\n\t\t\ti = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t// Skip accessing in sparse arrays\n\t\t\t\tif ( i in arr && arr[ i ] === elem ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar l = second.length,\n\t\t\ti = first.length,\n\t\t\tj = 0;\n\n\t\tif ( typeof l === \"number\" ) {\n\t\t\tfor ( ; j < l; j++ ) {\n\t\t\t\tfirst[ i++ ] = second[ j ];\n\t\t\t}\n\t\t} else {\n\t\t\twhile ( second[j] !== undefined ) {\n\t\t\t\tfirst[ i++ ] = second[ j++ ];\n\t\t\t}\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, inv ) {\n\t\tvar retVal,\n\t\t\tret = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length;\n\t\tinv = !!inv;\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\tretVal = !!callback( elems[ i ], i );\n\t\t\tif ( inv !== retVal ) {\n\t\t\t\tret.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\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\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[ ret.length ] = 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[ ret.length ] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn core_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 args, proxy, tmp;\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 = core_slice.call( arguments, 2 );\n\t\tproxy = function() {\n\t\t\treturn fn.apply( context || this, args.concat( core_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\t// Multifunctional method to get and set values of a collection\n\t// The value/s can optionally be executed if it's a function\n\taccess: function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\t\tvar i = 0,\n\t\t\tlength = elems.length,\n\t\t\tbulk = key == null;\n\n\t\t// Sets many values\n\t\tif ( jQuery.type( key ) === \"object\" ) {\n\t\t\tchainable = true;\n\t\t\tfor ( i in key ) {\n\t\t\t\tjQuery.access( elems, fn, i, key[i], true, emptyGet, raw );\n\t\t\t}\n\n\t\t// Sets one value\n\t\t} else if ( value !== undefined ) {\n\t\t\tchainable = true;\n\n\t\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\t\traw = true;\n\t\t\t}\n\n\t\t\tif ( bulk ) {\n\t\t\t\t// Bulk operations run against the entire set\n\t\t\t\tif ( raw ) {\n\t\t\t\t\tfn.call( elems, value );\n\t\t\t\t\tfn = null;\n\n\t\t\t\t// ...except when executing function values\n\t\t\t\t} else {\n\t\t\t\t\tbulk = fn;\n\t\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( fn ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tfn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn chainable ?\n\t\t\telems :\n\n\t\t\t// Gets\n\t\t\tbulk ?\n\t\t\t\tfn.call( elems ) :\n\t\t\t\tlength ? fn( elems[0], key ) : emptyGet;\n\t},\n\n\tnow: function() {\n\t\treturn ( new Date() ).getTime();\n\t}\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// Standards-based browsers support DOMContentLoaded\n\t\t} else if ( document.addEventListener ) {\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\n\t\t// If IE event model is used\n\t\t} else {\n\t\t\t// Ensure firing before onload, maybe late but safe also for iframes\n\t\t\tdocument.attachEvent( \"onreadystatechange\", completed );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.attachEvent( \"onload\", completed );\n\n\t\t\t// If IE and not a frame\n\t\t\t// continually check to see if the document is ready\n\t\t\tvar top = false;\n\n\t\t\ttry {\n\t\t\t\ttop = window.frameElement == null && document.documentElement;\n\t\t\t} catch(e) {}\n\n\t\t\tif ( top && top.doScroll ) {\n\t\t\t\t(function doScrollCheck() {\n\t\t\t\t\tif ( !jQuery.isReady ) {\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Use the trick by Diego Perini\n\t\t\t\t\t\t\t// http://javascript.nwbox.com/IEContentLoaded/\n\t\t\t\t\t\t\ttop.doScroll(\"left\");\n\t\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t\treturn setTimeout( doScrollCheck, 50 );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// detach all dom ready events\n\t\t\t\t\t\tdetach();\n\n\t\t\t\t\t\t// and execute any waiting functions\n\t\t\t\t\t\tjQuery.ready();\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t}\n\t\t}\n\t}\n\treturn readyList.promise( obj );\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\tvar length = obj.length,\n\t\ttype = jQuery.type( obj );\n\n\tif ( 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\" || type !== \"function\" &&\n\t\t( length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj );\n}\n\n// All jQuery objects should point back to these\nrootjQuery = jQuery(document);\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( core_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 // Flag to know if list is currently firing\n\t\tfiring,\n\t\t// 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// 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// First callback to fire (used internally by add and fireWith)\n\t\tfiringStart,\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\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\targs = args || [];\n\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\tif ( list && ( !fired || stack ) ) {\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};\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 action = tuple[ 0 ],\n\t\t\t\t\t\t\t\tfn = 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[ action + \"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 = core_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 ? core_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});\njQuery.support = (function() {\n\n\tvar support, all, a,\n\t\tinput, select, fragment,\n\t\topt, eventName, isSupported, i,\n\t\tdiv = document.createElement(\"div\");\n\n\t// Setup\n\tdiv.setAttribute( \"className\", \"t\" );\n\tdiv.innerHTML = \"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\";\n\n\t// Support tests won't run in some limited or non-browser environments\n\tall = div.getElementsByTagName(\"*\");\n\ta = div.getElementsByTagName(\"a\")[ 0 ];\n\tif ( !all || !a || !all.length ) {\n\t\treturn {};\n\t}\n\n\t// First batch of tests\n\tselect = document.createElement(\"select\");\n\topt = select.appendChild( document.createElement(\"option\") );\n\tinput = div.getElementsByTagName(\"input\")[ 0 ];\n\n\ta.style.cssText = \"top:1px;float:left;opacity:.5\";\n\tsupport = {\n\t\t// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)\n\t\tgetSetAttribute: div.className !== \"t\",\n\n\t\t// IE strips leading whitespace when .innerHTML is used\n\t\tleadingWhitespace: div.firstChild.nodeType === 3,\n\n\t\t// Make sure that tbody elements aren't automatically inserted\n\t\t// IE will insert them into empty tables\n\t\ttbody: !div.getElementsByTagName(\"tbody\").length,\n\n\t\t// Make sure that link elements get serialized correctly by innerHTML\n\t\t// This requires a wrapper element in IE\n\t\thtmlSerialize: !!div.getElementsByTagName(\"link\").length,\n\n\t\t// Get the style information from getAttribute\n\t\t// (IE uses .cssText instead)\n\t\tstyle: /top/.test( a.getAttribute(\"style\") ),\n\n\t\t// Make sure that URLs aren't manipulated\n\t\t// (IE normalizes it by default)\n\t\threfNormalized: a.getAttribute(\"href\") === \"/a\",\n\n\t\t// Make sure that element opacity exists\n\t\t// (IE uses filter instead)\n\t\t// Use a regex to work around a WebKit issue. See #5145\n\t\topacity: /^0.5/.test( a.style.opacity ),\n\n\t\t// Verify style float existence\n\t\t// (IE uses styleFloat instead of cssFloat)\n\t\tcssFloat: !!a.style.cssFloat,\n\n\t\t// Check the default checkbox/radio value (\"\" on WebKit; \"on\" elsewhere)\n\t\tcheckOn: !!input.value,\n\n\t\t// Make sure that a selected-by-default option has a working selected property.\n\t\t// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)\n\t\toptSelected: opt.selected,\n\n\t\t// Tests for enctype support on a form (#6743)\n\t\tenctype: !!document.createElement(\"form\").enctype,\n\n\t\t// Makes sure cloning an html5 element does not cause problems\n\t\t// Where outerHTML is undefined, this still works\n\t\thtml5Clone: document.createElement(\"nav\").cloneNode( true ).outerHTML !== \"<:nav></:nav>\",\n\n\t\t// jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode\n\t\tboxModel: document.compatMode === \"CSS1Compat\",\n\n\t\t// Will be defined later\n\t\tdeleteExpando: true,\n\t\tnoCloneEvent: true,\n\t\tinlineBlockNeedsLayout: false,\n\t\tshrinkWrapBlocks: false,\n\t\treliableMarginRight: true,\n\t\tboxSizingReliable: true,\n\t\tpixelPosition: false\n\t};\n\n\t// Make sure checked status is properly cloned\n\tinput.checked = true;\n\tsupport.noCloneChecked = input.cloneNode( true ).checked;\n\n\t// Make sure that the options inside disabled selects aren't marked as disabled\n\t// (WebKit marks them as disabled)\n\tselect.disabled = true;\n\tsupport.optDisabled = !opt.disabled;\n\n\t// Support: IE<9\n\ttry {\n\t\tdelete div.test;\n\t} catch( e ) {\n\t\tsupport.deleteExpando = false;\n\t}\n\n\t// Check if we can trust getAttribute(\"value\")\n\tinput = document.createElement(\"input\");\n\tinput.setAttribute( \"value\", \"\" );\n\tsupport.input = input.getAttribute( \"value\" ) === \"\";\n\n\t// Check if an input maintains its value after becoming a radio\n\tinput.value = \"t\";\n\tinput.setAttribute( \"type\", \"radio\" );\n\tsupport.radioValue = input.value === \"t\";\n\n\t// #11217 - WebKit loses check when the name is after the checked attribute\n\tinput.setAttribute( \"checked\", \"t\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tfragment = document.createDocumentFragment();\n\tfragment.appendChild( input );\n\n\t// Check if a disconnected checkbox will retain its checked\n\t// value of true after appended to the DOM (IE6/7)\n\tsupport.appendChecked = input.checked;\n\n\t// WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE<9\n\t// Opera does not clone events (and typeof div.attachEvent === undefined).\n\t// IE9-10 clones events bound via attachEvent, but they don't trigger with .click()\n\tif ( div.attachEvent ) {\n\t\tdiv.attachEvent( \"onclick\", function() {\n\t\t\tsupport.noCloneEvent = false;\n\t\t});\n\n\t\tdiv.cloneNode( true ).click();\n\t}\n\n\t// Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)\n\t// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php\n\tfor ( i in { submit: true, change: true, focusin: true }) {\n\t\tdiv.setAttribute( eventName = \"on\" + i, \"t\" );\n\n\t\tsupport[ i + \"Bubbles\" ] = eventName in window || div.attributes[ eventName ].expando === false;\n\t}\n\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\t// Run tests that need a body at doc ready\n\tjQuery(function() {\n\t\tvar container, marginDiv, tds,\n\t\t\tdivReset = \"padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;\",\n\t\t\tbody = document.getElementsByTagName(\"body\")[0];\n\n\t\tif ( !body ) {\n\t\t\t// Return for frameset docs that don't have a body\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer = document.createElement(\"div\");\n\t\tcontainer.style.cssText = \"border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px\";\n\n\t\tbody.appendChild( container ).appendChild( div );\n\n\t\t// Support: IE8\n\t\t// Check if table cells still have offsetWidth/Height when they are set\n\t\t// to display:none and there are still other visible table cells in a\n\t\t// table row; if so, offsetWidth/Height are not reliable for use when\n\t\t// determining if an element has been hidden directly using\n\t\t// display:none (it is still safe to use offsets if a parent element is\n\t\t// hidden; don safety goggles and see bug #4512 for more information).\n\t\tdiv.innerHTML = \"<table><tr><td></td><td>t</td></tr></table>\";\n\t\ttds = div.getElementsByTagName(\"td\");\n\t\ttds[ 0 ].style.cssText = \"padding:0;margin:0;border:0;display:none\";\n\t\tisSupported = ( tds[ 0 ].offsetHeight === 0 );\n\n\t\ttds[ 0 ].style.display = \"\";\n\t\ttds[ 1 ].style.display = \"none\";\n\n\t\t// Support: IE8\n\t\t// Check if empty table cells still have offsetWidth/Height\n\t\tsupport.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );\n\n\t\t// Check box-sizing and margin behavior\n\t\tdiv.innerHTML = \"\";\n\t\tdiv.style.cssText = \"box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;\";\n\t\tsupport.boxSizing = ( div.offsetWidth === 4 );\n\t\tsupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );\n\n\t\t// Use window.getComputedStyle because jsdom on node.js will break without it.\n\t\tif ( window.getComputedStyle ) {\n\t\t\tsupport.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== \"1%\";\n\t\t\tsupport.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: \"4px\" } ).width === \"4px\";\n\n\t\t\t// Check if div with explicit width and no margin-right incorrectly\n\t\t\t// gets computed margin-right based on width of container. (#3333)\n\t\t\t// Fails in WebKit before Feb 2011 nightlies\n\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\tmarginDiv = div.appendChild( document.createElement(\"div\") );\n\t\t\tmarginDiv.style.cssText = div.style.cssText = divReset;\n\t\t\tmarginDiv.style.marginRight = marginDiv.style.width = \"0\";\n\t\t\tdiv.style.width = \"1px\";\n\n\t\t\tsupport.reliableMarginRight =\n\t\t\t\t!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );\n\t\t}\n\n\t\tif ( typeof div.style.zoom !== core_strundefined ) {\n\t\t\t// Support: IE<8\n\t\t\t// Check if natively block-level elements act like inline-block\n\t\t\t// elements when setting their display to 'inline' and giving\n\t\t\t// them layout\n\t\t\tdiv.innerHTML = \"\";\n\t\t\tdiv.style.cssText = divReset + \"width:1px;padding:1px;display:inline;zoom:1\";\n\t\t\tsupport.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );\n\n\t\t\t// Support: IE6\n\t\t\t// Check if elements with layout shrink-wrap their children\n\t\t\tdiv.style.display = \"block\";\n\t\t\tdiv.innerHTML = \"<div></div>\";\n\t\t\tdiv.firstChild.style.width = \"5px\";\n\t\t\tsupport.shrinkWrapBlocks = ( div.offsetWidth !== 3 );\n\n\t\t\tif ( support.inlineBlockNeedsLayout ) {\n\t\t\t\t// Prevent IE 6 from affecting layout for positioned elements #11048\n\t\t\t\t// Prevent IE from shrinking the body in IE 7 mode #12869\n\t\t\t\t// Support: IE<8\n\t\t\t\tbody.style.zoom = 1;\n\t\t\t}\n\t\t}\n\n\t\tbody.removeChild( container );\n\n\t\t// Null elements to avoid leaks in IE\n\t\tcontainer = div = tds = marginDiv = null;\n\t});\n\n\t// Null elements to avoid leaks in IE\n\tall = select = fragment = opt = a = input = null;\n\n\treturn support;\n})();\n\nvar rbrace = /(?:\\{[\\s\\S]*\\}|\\[[\\s\\S]*\\])$/,\n\trmultiDash = /([A-Z])/g;\n\nfunction internalData( elem, name, data, pvt /* Internal Use Only */ ){\n\tif ( !jQuery.acceptData( elem ) ) {\n\t\treturn;\n\t}\n\n\tvar thisCache, ret,\n\t\tinternalKey = jQuery.expando,\n\t\tgetByName = typeof name === \"string\",\n\n\t\t// We have to handle DOM nodes and JS objects differently because IE6-7\n\t\t// can't GC object references properly across the DOM-JS boundary\n\t\tisNode = elem.nodeType,\n\n\t\t// Only DOM nodes need the global jQuery cache; JS object data is\n\t\t// attached directly to the object so GC can occur automatically\n\t\tcache = isNode ? jQuery.cache : elem,\n\n\t\t// Only defining an ID for JS objects if its cache already exists allows\n\t\t// the code to shortcut on the same path as a DOM node with no cache\n\t\tid = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;\n\n\t// Avoid doing any more work than we need to when trying to get data on an\n\t// object that has no data at all\n\tif ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {\n\t\treturn;\n\t}\n\n\tif ( !id ) {\n\t\t// Only DOM nodes need a new unique ID for each element since their data\n\t\t// ends up in the global cache\n\t\tif ( isNode ) {\n\t\t\telem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;\n\t\t} else {\n\t\t\tid = internalKey;\n\t\t}\n\t}\n\n\tif ( !cache[ id ] ) {\n\t\tcache[ id ] = {};\n\n\t\t// Avoids exposing jQuery metadata on plain JS objects when the object\n\t\t// is serialized using JSON.stringify\n\t\tif ( !isNode ) {\n\t\t\tcache[ id ].toJSON = jQuery.noop;\n\t\t}\n\t}\n\n\t// An object can be passed to jQuery.data instead of a key/value pair; this gets\n\t// shallow copied over onto the existing cache\n\tif ( typeof name === \"object\" || typeof name === \"function\" ) {\n\t\tif ( pvt ) {\n\t\t\tcache[ id ] = jQuery.extend( cache[ id ], name );\n\t\t} else {\n\t\t\tcache[ id ].data = jQuery.extend( cache[ id ].data, name );\n\t\t}\n\t}\n\n\tthisCache = cache[ id ];\n\n\t// jQuery data() is stored in a separate object inside the object's internal data\n\t// cache in order to avoid key collisions between internal data and user-defined\n\t// data.\n\tif ( !pvt ) {\n\t\tif ( !thisCache.data ) {\n\t\t\tthisCache.data = {};\n\t\t}\n\n\t\tthisCache = thisCache.data;\n\t}\n\n\tif ( data !== undefined ) {\n\t\tthisCache[ jQuery.camelCase( name ) ] = data;\n\t}\n\n\t// Check for both converted-to-camel and non-converted data property names\n\t// If a data property was specified\n\tif ( getByName ) {\n\n\t\t// First Try to find as-is property data\n\t\tret = thisCache[ name ];\n\n\t\t// Test for null|undefined property data\n\t\tif ( ret == null ) {\n\n\t\t\t// Try to find the camelCased property\n\t\t\tret = thisCache[ jQuery.camelCase( name ) ];\n\t\t}\n\t} else {\n\t\tret = thisCache;\n\t}\n\n\treturn ret;\n}\n\nfunction internalRemoveData( elem, name, pvt ) {\n\tif ( !jQuery.acceptData( elem ) ) {\n\t\treturn;\n\t}\n\n\tvar i, l, thisCache,\n\t\tisNode = elem.nodeType,\n\n\t\t// See jQuery.data for more information\n\t\tcache = isNode ? jQuery.cache : elem,\n\t\tid = isNode ? elem[ jQuery.expando ] : jQuery.expando;\n\n\t// If there is already no cache entry for this object, there is no\n\t// purpose in continuing\n\tif ( !cache[ id ] ) {\n\t\treturn;\n\t}\n\n\tif ( name ) {\n\n\t\tthisCache = pvt ? cache[ id ] : cache[ id ].data;\n\n\t\tif ( thisCache ) {\n\n\t\t\t// Support array or space separated string names for data keys\n\t\t\tif ( !jQuery.isArray( name ) ) {\n\n\t\t\t\t// try the string as a key before any manipulation\n\t\t\t\tif ( name in thisCache ) {\n\t\t\t\t\tname = [ name ];\n\t\t\t\t} else {\n\n\t\t\t\t\t// split the camel cased version by spaces unless a key with the spaces exists\n\t\t\t\t\tname = jQuery.camelCase( name );\n\t\t\t\t\tif ( name in thisCache ) {\n\t\t\t\t\t\tname = [ name ];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tname = name.split(\" \");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\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 = name.concat( jQuery.map( name, jQuery.camelCase ) );\n\t\t\t}\n\n\t\t\tfor ( i = 0, l = name.length; i < l; i++ ) {\n\t\t\t\tdelete thisCache[ name[i] ];\n\t\t\t}\n\n\t\t\t// If there is no data left in the cache, we want to continue\n\t\t\t// and let the cache object itself get destroyed\n\t\t\tif ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t// See jQuery.data for more information\n\tif ( !pvt ) {\n\t\tdelete cache[ id ].data;\n\n\t\t// Don't destroy the parent cache unless the internal data object\n\t\t// had been the only thing left in it\n\t\tif ( !isEmptyDataObject( cache[ id ] ) ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// Destroy the cache\n\tif ( isNode ) {\n\t\tjQuery.cleanData( [ elem ], true );\n\n\t// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)\n\t} else if ( jQuery.support.deleteExpando || cache != cache.window ) {\n\t\tdelete cache[ id ];\n\n\t// When all else fails, null\n\t} else {\n\t\tcache[ id ] = null;\n\t}\n}\n\njQuery.extend({\n\tcache: {},\n\n\t// Unique for each copy of jQuery on the page\n\t// Non-digits removed to match rinlinejQuery\n\texpando: \"jQuery\" + ( core_version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// The following elements throw uncatchable exceptions if you\n\t// attempt to add expando properties to them.\n\tnoData: {\n\t\t\"embed\": true,\n\t\t// Ban all objects except for Flash (which handle expandos)\n\t\t\"object\": \"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",\n\t\t\"applet\": true\n\t},\n\n\thasData: function( elem ) {\n\t\telem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];\n\t\treturn !!elem && !isEmptyDataObject( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn internalData( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\treturn internalRemoveData( elem, name );\n\t},\n\n\t// For internal use only.\n\t_data: function( elem, name, data ) {\n\t\treturn internalData( elem, name, data, true );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\treturn internalRemoveData( elem, name, true );\n\t},\n\n\t// A method for determining if a DOM node can handle the data expando\n\tacceptData: function( elem ) {\n\t\t// Do not set data on non-element because it will not be cleared (#8335).\n\t\tif ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];\n\n\t\t// nodes accept data unless otherwise specified; rejection can be conditional\n\t\treturn !noData || noData !== true && elem.getAttribute(\"classid\") === noData;\n\t}\n});\n\njQuery.fn.extend({\n\tdata: function( key, value ) {\n\t\tvar attrs, name,\n\t\t\telem = this[0],\n\t\t\ti = 0,\n\t\t\tdata = null;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = jQuery.data( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !jQuery._data( elem, \"parsedAttrs\" ) ) {\n\t\t\t\t\tattrs = elem.attributes;\n\t\t\t\t\tfor ( ; i < attrs.length; i++ ) {\n\t\t\t\t\t\tname = attrs[i].name;\n\n\t\t\t\t\t\tif ( !name.indexOf( \"data-\" ) ) {\n\t\t\t\t\t\t\tname = jQuery.camelCase( name.slice(5) );\n\n\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tjQuery._data( elem, \"parsedAttrs\", 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\tjQuery.data( this, key );\n\t\t\t});\n\t\t}\n\n\t\treturn jQuery.access( this, function( value ) {\n\n\t\t\tif ( value === undefined ) {\n\t\t\t\t// Try to fetch any internally stored data first\n\t\t\t\treturn elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;\n\t\t\t}\n\n\t\t\tthis.each(function() {\n\t\t\t\tjQuery.data( this, key, value );\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\tjQuery.removeData( this, key );\n\t\t});\n\t}\n});\n\nfunction dataAttr( elem, key, data ) {\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\n\t\tvar name = \"data-\" + key.replace( rmultiDash, \"-$1\" ).toLowerCase();\n\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\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\tjQuery.data( elem, key, data );\n\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\n\treturn data;\n}\n\n// checks a cache object for emptiness\nfunction isEmptyDataObject( obj ) {\n\tvar name;\n\tfor ( name in obj ) {\n\n\t\t// if the public data object is empty, the private is still empty\n\t\tif ( name === \"data\" && jQuery.isEmptyObject( obj[name] ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( name !== \"toJSON\" ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\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 = jQuery._data( 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 = jQuery._data( 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\thooks.cur = fn;\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 intended for public consumption - generates a queueHooks object, or returns the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn jQuery._data( elem, key ) || jQuery._data( elem, key, {\n\t\t\tempty: jQuery.Callbacks(\"once memory\").add(function() {\n\t\t\t\tjQuery._removeData( elem, type + \"queue\" );\n\t\t\t\tjQuery._removeData( elem, 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\t// Based off of the plugin by Clint Helfers, with permission.\n\t// http://blindsignals.com/index.php/2009/07/jquery-delay/\n\tdelay: function( time, type ) {\n\t\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\t\ttype = type || \"fx\";\n\n\t\treturn this.queue( type, function( next, hooks ) {\n\t\t\tvar timeout = setTimeout( next, time );\n\t\t\thooks.stop = function() {\n\t\t\t\tclearTimeout( timeout );\n\t\t\t};\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 = jQuery._data( 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 nodeHook, boolHook,\n\trclass = /[\\t\\r\\n]/g,\n\trreturn = /\\r/g,\n\trfocusable = /^(?:input|select|textarea|button|object)$/i,\n\trclickable = /^(?:a|area)$/i,\n\trboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,\n\truseDefault = /^(?:checked|selected)$/i,\n\tgetSetAttribute = jQuery.support.getSetAttribute,\n\tgetSetInput = jQuery.support.input;\n\njQuery.fn.extend({\n\tattr: function( name, value ) {\n\t\treturn jQuery.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\tprop: function( name, value ) {\n\t\treturn jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\tname = jQuery.propFix[ name ] || name;\n\t\treturn this.each(function() {\n\t\t\t// try/catch handles cases where IE balks (such as removing a property on window)\n\t\t\ttry {\n\t\t\t\tthis[ name ] = undefined;\n\t\t\t\tdelete this[ name ];\n\t\t\t} catch( e ) {}\n\t\t});\n\t},\n\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j,\n\t\t\ti = 0,\n\t\t\tlen = this.length,\n\t\t\tproceed = typeof value === \"string\" && value;\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( core_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\t\t\t\t\telem.className = jQuery.trim( cur );\n\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,\n\t\t\ti = 0,\n\t\t\tlen = this.length,\n\t\t\tproceed = arguments.length === 0 || typeof value === \"string\" && value;\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( core_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\t\t\t\t\telem.className = value ? jQuery.trim( cur ) : \"\";\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\t\t\tisBool = typeof stateVal === \"boolean\";\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\tstate = stateVal,\n\t\t\t\t\tclassNames = value.match( core_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\tstate = isBool ? state : !self.hasClass( className );\n\t\t\t\t\tself[ state ? \"addClass\" : \"removeClass\" ]( className );\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( type === core_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\tjQuery._data( 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 ? \"\" : jQuery._data( 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\tval: function( value ) {\n\t\tvar ret, hooks, 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\t\t\t\tself = jQuery(this);\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, self.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\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\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\t// attributes.value is undefined in Blackberry 4.7 but\n\t\t\t\t// uses .value. See #6932\n\t\t\t\tvar val = elem.attributes.value;\n\t\t\t\treturn !val || val.specified ? elem.value : elem.text;\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// oldIE 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( jQuery.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 values = jQuery.makeArray( value );\n\n\t\t\t\tjQuery(elem).find(\"option\").each(function() {\n\t\t\t\t\tthis.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;\n\t\t\t\t});\n\n\t\t\t\tif ( !values.length ) {\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\tattr: function( elem, name, value ) {\n\t\tvar hooks, notxml, 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 === core_strundefined ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\t// All attributes are lowercase\n\t\t// Grab necessary hook if one is defined\n\t\tif ( notxml ) {\n\t\t\tname = name.toLowerCase();\n\t\t\thooks = jQuery.attrHooks[ name ] || ( rboolean.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 && notxml && \"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 && notxml && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\treturn ret;\n\n\t\t} else {\n\n\t\t\t// In IE9+, Flash objects don't have .getAttribute (#12945)\n\t\t\t// Support: IE9+\n\t\t\tif ( typeof elem.getAttribute !== core_strundefined ) {\n\t\t\t\tret =  elem.getAttribute( name );\n\t\t\t}\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( core_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 ( rboolean.test( name ) ) {\n\t\t\t\t\t// Set corresponding property to false for boolean attributes\n\t\t\t\t\t// Also clear defaultChecked/defaultSelected (if appropriate) for IE<8\n\t\t\t\t\tif ( !getSetAttribute && ruseDefault.test( name ) ) {\n\t\t\t\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] =\n\t\t\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t\t}\n\n\t\t\t\t// See #9699 for explanation of this approach (setting first, then removal)\n\t\t\t\t} else {\n\t\t\t\t\tjQuery.attr( elem, name, \"\" );\n\t\t\t\t}\n\n\t\t\t\telem.removeAttribute( getSetAttribute ? name : propName );\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 ( !jQuery.support.radioValue && value === \"radio\" && jQuery.nodeName(elem, \"input\") ) {\n\t\t\t\t\t// Setting the type on a radio button after the value resets the value in IE6-9\n\t\t\t\t\t// Reset value to default in case type is set after value during creation\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\tpropFix: {\n\t\ttabindex: \"tabIndex\",\n\t\treadonly: \"readOnly\",\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\",\n\t\tmaxlength: \"maxLength\",\n\t\tcellspacing: \"cellSpacing\",\n\t\tcellpadding: \"cellPadding\",\n\t\trowspan: \"rowSpan\",\n\t\tcolspan: \"colSpan\",\n\t\tusemap: \"useMap\",\n\t\tframeborder: \"frameBorder\",\n\t\tcontenteditable: \"contentEditable\"\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\tif ( 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\treturn ( elem[ name ] = value );\n\t\t\t}\n\n\t\t} else {\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\treturn elem[ name ];\n\t\t\t}\n\t\t}\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\t\t\t\t// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set\n\t\t\t\t// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\tvar attributeNode = elem.getAttributeNode(\"tabindex\");\n\n\t\t\t\treturn attributeNode && attributeNode.specified ?\n\t\t\t\t\tparseInt( attributeNode.value, 10 ) :\n\t\t\t\t\trfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?\n\t\t\t\t\t\t0 :\n\t\t\t\t\t\tundefined;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Hook for boolean attributes\nboolHook = {\n\tget: function( elem, name ) {\n\t\tvar\n\t\t\t// Use .prop to determine if this attribute is understood as boolean\n\t\t\tprop = jQuery.prop( elem, name ),\n\n\t\t\t// Fetch it accordingly\n\t\t\tattr = typeof prop === \"boolean\" && elem.getAttribute( name ),\n\t\t\tdetail = typeof prop === \"boolean\" ?\n\n\t\t\t\tgetSetInput && getSetAttribute ?\n\t\t\t\t\tattr != null :\n\t\t\t\t\t// oldIE fabricates an empty string for missing boolean attributes\n\t\t\t\t\t// and conflates checked/selected into attroperties\n\t\t\t\t\truseDefault.test( name ) ?\n\t\t\t\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] :\n\t\t\t\t\t\t!!attr :\n\n\t\t\t\t// fetch an attribute node for properties not recognized as boolean\n\t\t\t\telem.getAttributeNode( name );\n\n\t\treturn detail && detail.value !== false ?\n\t\t\tname.toLowerCase() :\n\t\t\tundefined;\n\t},\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 if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {\n\t\t\t// IE<8 needs the *property* name\n\t\t\telem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );\n\n\t\t// Use defaultChecked and defaultSelected for oldIE\n\t\t} else {\n\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] = elem[ name ] = true;\n\t\t}\n\n\t\treturn name;\n\t}\n};\n\n// fix oldIE value attroperty\nif ( !getSetInput || !getSetAttribute ) {\n\tjQuery.attrHooks.value = {\n\t\tget: function( elem, name ) {\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\treturn jQuery.nodeName( elem, \"input\" ) ?\n\n\t\t\t\t// Ignore the value *property* by using defaultValue\n\t\t\t\telem.defaultValue :\n\n\t\t\t\tret && ret.specified ? ret.value : undefined;\n\t\t},\n\t\tset: function( elem, value, name ) {\n\t\t\tif ( jQuery.nodeName( elem, \"input\" ) ) {\n\t\t\t\t// Does not return so that setAttribute is also used\n\t\t\t\telem.defaultValue = value;\n\t\t\t} else {\n\t\t\t\t// Use nodeHook if defined (#1954); otherwise setAttribute is fine\n\t\t\t\treturn nodeHook && nodeHook.set( elem, value, name );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// IE6/7 do not support getting/setting some attributes with get/setAttribute\nif ( !getSetAttribute ) {\n\n\t// Use this for any attribute in IE6/7\n\t// This fixes almost every IE6/7 issue\n\tnodeHook = jQuery.valHooks.button = {\n\t\tget: function( elem, name ) {\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\treturn ret && ( name === \"id\" || name === \"name\" || name === \"coords\" ? ret.value !== \"\" : ret.specified ) ?\n\t\t\t\tret.value :\n\t\t\t\tundefined;\n\t\t},\n\t\tset: function( elem, value, name ) {\n\t\t\t// Set the existing or create a new attribute node\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\tif ( !ret ) {\n\t\t\t\telem.setAttributeNode(\n\t\t\t\t\t(ret = elem.ownerDocument.createAttribute( name ))\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tret.value = value += \"\";\n\n\t\t\t// Break association with cloned elements by also using setAttribute (#9646)\n\t\t\treturn name === \"value\" || value === elem.getAttribute( name ) ?\n\t\t\t\tvalue :\n\t\t\t\tundefined;\n\t\t}\n\t};\n\n\t// Set contenteditable to false on removals(#10429)\n\t// Setting to empty string throws an error as an invalid value\n\tjQuery.attrHooks.contenteditable = {\n\t\tget: nodeHook.get,\n\t\tset: function( elem, value, name ) {\n\t\t\tnodeHook.set( elem, value === \"\" ? false : value, name );\n\t\t}\n\t};\n\n\t// Set width and height to auto instead of 0 on empty string( Bug #8150 )\n\t// This is for removals\n\tjQuery.each([ \"width\", \"height\" ], function( i, name ) {\n\t\tjQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( value === \"\" ) {\n\t\t\t\t\telem.setAttribute( name, \"auto\" );\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n\n// Some attributes require a special call on IE\n// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !jQuery.support.hrefNormalized ) {\n\tjQuery.each([ \"href\", \"src\", \"width\", \"height\" ], function( i, name ) {\n\t\tjQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar ret = elem.getAttribute( name, 2 );\n\t\t\t\treturn ret == null ? undefined : ret;\n\t\t\t}\n\t\t});\n\t});\n\n\t// href/src property should get the full normalized URL (#10299/#12915)\n\tjQuery.each([ \"href\", \"src\" ], function( i, name ) {\n\t\tjQuery.propHooks[ name ] = {\n\t\t\tget: function( elem ) {\n\t\t\t\treturn elem.getAttribute( name, 4 );\n\t\t\t}\n\t\t};\n\t});\n}\n\nif ( !jQuery.support.style ) {\n\tjQuery.attrHooks.style = {\n\t\tget: function( elem ) {\n\t\t\t// Return undefined in the case of empty string\n\t\t\t// Note: IE uppercases css property names, but if we were to .toLowerCase()\n\t\t\t// .cssText, that would destroy case senstitivity in URL's, like in \"background\"\n\t\t\treturn elem.style.cssText || undefined;\n\t\t},\n\t\tset: function( elem, value ) {\n\t\t\treturn ( elem.style.cssText = value + \"\" );\n\t\t}\n\t};\n}\n\n// Safari mis-reports the default selected property of an option\n// Accessing the parent's selectedIndex property fixes it\nif ( !jQuery.support.optSelected ) {\n\tjQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {\n\t\tget: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\t// Make sure that it also works with optgroups, see #5701\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t});\n}\n\n// IE6/7 call enctype encoding\nif ( !jQuery.support.enctype ) {\n\tjQuery.propFix.enctype = \"encoding\";\n}\n\n// Radios and checkboxes getter/setter\nif ( !jQuery.support.checkOn ) {\n\tjQuery.each([ \"radio\", \"checkbox\" ], function() {\n\t\tjQuery.valHooks[ this ] = {\n\t\t\tget: function( elem ) {\n\t\t\t\t// Handle the case where in Webkit \"\" is returned instead of \"on\" if a value isn't specified\n\t\t\t\treturn elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n\t\t\t}\n\t\t};\n\t});\n}\njQuery.each([ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = jQuery.extend( jQuery.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});\nvar rformElems = /^(?:input|select|textarea)$/i,\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|contextmenu)|click/,\n\trfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)$/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\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\t\tvar tmp, events, t, handleObjIn,\n\t\t\tspecial, eventHandle, handleObj,\n\t\t\thandlers, type, namespaces, origType,\n\t\t\telemData = jQuery._data( 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 !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?\n\t\t\t\t\tjQuery.event.dispatch.apply( eventHandle.elem, arguments ) :\n\t\t\t\t\tundefined;\n\t\t\t};\n\t\t\t// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events\n\t\t\teventHandle.elem = elem;\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\t// jQuery(...).bind(\"mouseover mouseout\", fn);\n\t\ttypes = ( types || \"\" ).match( core_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// 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/attachEvent 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\t// Bind the global event handler to the element\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle, false );\n\n\t\t\t\t\t} else if ( elem.attachEvent ) {\n\t\t\t\t\t\telem.attachEvent( \"on\" + type, eventHandle );\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\t// Nullify elem to prevent memory leaks in IE\n\t\telem = null;\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\t\tvar j, handleObj, tmp,\n\t\t\torigCount, t, events,\n\t\t\tspecial, handlers, type,\n\t\t\tnamespaces, origType,\n\t\t\telemData = jQuery.hasData( elem ) && jQuery._data( 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( core_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\n\t\t\t// removeData also checks for emptiness and clears the expando if empty\n\t\t\t// so use it instead of delete\n\t\t\tjQuery._removeData( elem, \"events\" );\n\t\t}\n\t},\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\t\tvar handle, ontype, cur,\n\t\t\tbubbleType, special, tmp, i,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = core_hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = core_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\tevent.isTrigger = true;\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 = ( jQuery._data( cur, \"events\" ) || {} )[ event.type ] && jQuery._data( 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 && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {\n\t\t\t\tevent.preventDefault();\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( elem.ownerDocument, data ) === false) &&\n\t\t\t\t!(type === \"click\" && jQuery.nodeName( elem, \"a\" )) && jQuery.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// Can't use an .isFunction() check here because IE6/7 fails that test.\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 && 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\ttry {\n\t\t\t\t\t\telem[ type ]();\n\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t// IE<9 dies on focus/blur to hidden element (#1486,#12518)\n\t\t\t\t\t\t// only reproducible on winXP IE8 native, not IE9 in IE8 mode\n\t\t\t\t\t}\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, ret, handleObj, matched, j,\n\t\t\thandlerQueue = [],\n\t\t\targs = core_slice.call( arguments ),\n\t\t\thandlers = ( jQuery._data( 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\n\t\t\t\t// 2) have namespace(s) 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 sel, handleObj, matches, i,\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 check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && (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\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: IE<9\n\t\t// Fix target property (#1925)\n\t\tif ( !event.target ) {\n\t\t\tevent.target = originalEvent.srcElement || document;\n\t\t}\n\n\t\t// Support: Chrome 23+, Safari?\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\t// Support: IE<9\n\t\t// For mouse/key events, metaKey==false if it's undefined (#3368, #11328)\n\t\tevent.metaKey = !!event.metaKey;\n\n\t\treturn fixHook.filter ? fixHook.filter( event, originalEvent ) : event;\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 fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\t\t\tvar body, eventDoc, doc,\n\t\t\t\tbutton = original.button,\n\t\t\t\tfromElement = original.fromElement;\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 relatedTarget, if necessary\n\t\t\tif ( !event.relatedTarget && fromElement ) {\n\t\t\t\tevent.relatedTarget = fromElement === event.target ? original.toElement : fromElement;\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\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\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 ( jQuery.nodeName( this, \"input\" ) && this.type === \"checkbox\" && this.click ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\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 !== document.activeElement && this.focus ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.focus();\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t// Support: IE<9\n\t\t\t\t\t\t// If we error on focus to hidden element (#1486, #12518),\n\t\t\t\t\t\t// let .trigger() run the handlers\n\t\t\t\t\t}\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 === document.activeElement && 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\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Even when returnValue equals to undefined Firefox will still show alert\n\t\t\t\tif ( event.result !== undefined ) {\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{ type: 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 = document.removeEventListener ?\n\tfunction( elem, type, handle ) {\n\t\tif ( elem.removeEventListener ) {\n\t\t\telem.removeEventListener( type, handle, false );\n\t\t}\n\t} :\n\tfunction( elem, type, handle ) {\n\t\tvar name = \"on\" + type;\n\n\t\tif ( elem.detachEvent ) {\n\n\t\t\t// #8545, #7054, preventing memory leaks for custom events in IE6-8\n\t\t\t// detachEvent needed property on element, by name of that event, to properly expose it to GC\n\t\t\tif ( typeof elem[ name ] === core_strundefined ) {\n\t\t\t\telem[ name ] = null;\n\t\t\t}\n\n\t\t\telem.detachEvent( name, handle );\n\t\t}\n\t};\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 || src.returnValue === false ||\n\t\t\tsrc.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;\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\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If preventDefault exists, run it on the original event\n\t\tif ( e.preventDefault ) {\n\t\t\te.preventDefault();\n\n\t\t// Support: IE\n\t\t// Otherwise set the returnValue property of the original event to false\n\t\t} else {\n\t\t\te.returnValue = false;\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\t\t// If stopPropagation exists, run it on the original event\n\t\tif ( e.stopPropagation ) {\n\t\t\te.stopPropagation();\n\t\t}\n\n\t\t// Support: IE\n\t\t// Set the cancelBubble property of the original event to true\n\t\te.cancelBubble = true;\n\t},\n\tstopImmediatePropagation: function() {\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\njQuery.each({\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\"\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// IE submit delegation\nif ( !jQuery.support.submitBubbles ) {\n\n\tjQuery.event.special.submit = {\n\t\tsetup: function() {\n\t\t\t// Only need this for delegated form submit events\n\t\t\tif ( jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Lazy-add a submit handler when a descendant form may potentially be submitted\n\t\t\tjQuery.event.add( this, \"click._submit keypress._submit\", function( e ) {\n\t\t\t\t// Node name check avoids a VML-related crash in IE (#9807)\n\t\t\t\tvar elem = e.target,\n\t\t\t\t\tform = jQuery.nodeName( elem, \"input\" ) || jQuery.nodeName( elem, \"button\" ) ? elem.form : undefined;\n\t\t\t\tif ( form && !jQuery._data( form, \"submitBubbles\" ) ) {\n\t\t\t\t\tjQuery.event.add( form, \"submit._submit\", function( event ) {\n\t\t\t\t\t\tevent._submit_bubble = true;\n\t\t\t\t\t});\n\t\t\t\t\tjQuery._data( form, \"submitBubbles\", true );\n\t\t\t\t}\n\t\t\t});\n\t\t\t// return undefined since we don't need an event listener\n\t\t},\n\n\t\tpostDispatch: function( event ) {\n\t\t\t// If form was submitted by the user, bubble the event up the tree\n\t\t\tif ( event._submit_bubble ) {\n\t\t\t\tdelete event._submit_bubble;\n\t\t\t\tif ( this.parentNode && !event.isTrigger ) {\n\t\t\t\t\tjQuery.event.simulate( \"submit\", this.parentNode, event, true );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tteardown: function() {\n\t\t\t// Only need this for delegated form submit events\n\t\t\tif ( jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Remove delegated handlers; cleanData eventually reaps submit handlers attached above\n\t\t\tjQuery.event.remove( this, \"._submit\" );\n\t\t}\n\t};\n}\n\n// IE change delegation and checkbox/radio fix\nif ( !jQuery.support.changeBubbles ) {\n\n\tjQuery.event.special.change = {\n\n\t\tsetup: function() {\n\n\t\t\tif ( rformElems.test( this.nodeName ) ) {\n\t\t\t\t// IE doesn't fire change on a check/radio until blur; trigger it on click\n\t\t\t\t// after a propertychange. Eat the blur-change in special.change.handle.\n\t\t\t\t// This still fires onchange a second time for check/radio after blur.\n\t\t\t\tif ( this.type === \"checkbox\" || this.type === \"radio\" ) {\n\t\t\t\t\tjQuery.event.add( this, \"propertychange._change\", function( event ) {\n\t\t\t\t\t\tif ( event.originalEvent.propertyName === \"checked\" ) {\n\t\t\t\t\t\t\tthis._just_changed = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tjQuery.event.add( this, \"click._change\", function( event ) {\n\t\t\t\t\t\tif ( this._just_changed && !event.isTrigger ) {\n\t\t\t\t\t\t\tthis._just_changed = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Allow triggered, simulated change events (#11500)\n\t\t\t\t\t\tjQuery.event.simulate( \"change\", this, event, true );\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// Delegated event; lazy-add a change handler on descendant inputs\n\t\t\tjQuery.event.add( this, \"beforeactivate._change\", function( e ) {\n\t\t\t\tvar elem = e.target;\n\n\t\t\t\tif ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, \"changeBubbles\" ) ) {\n\t\t\t\t\tjQuery.event.add( elem, \"change._change\", function( event ) {\n\t\t\t\t\t\tif ( this.parentNode && !event.isSimulated && !event.isTrigger ) {\n\t\t\t\t\t\t\tjQuery.event.simulate( \"change\", this.parentNode, event, true );\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tjQuery._data( elem, \"changeBubbles\", true );\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\thandle: function( event ) {\n\t\t\tvar elem = event.target;\n\n\t\t\t// Swallow native change events from checkbox/radio, we already triggered them above\n\t\t\tif ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== \"radio\" && elem.type !== \"checkbox\") ) {\n\t\t\t\treturn event.handleObj.handler.apply( this, arguments );\n\t\t\t}\n\t\t},\n\n\t\tteardown: function() {\n\t\t\tjQuery.event.remove( this, \"._change\" );\n\n\t\t\treturn !rformElems.test( this.nodeName );\n\t\t}\n\t};\n}\n\n// Create \"bubbling\" focus and blur events\nif ( !jQuery.support.focusinBubbles ) {\n\tjQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler while someone wants focusin/focusout\n\t\tvar attaches = 0,\n\t\t\thandler = 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\tif ( attaches++ === 0 ) {\n\t\t\t\t\tdocument.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tif ( --attaches === 0 ) {\n\t\t\t\t\tdocument.removeEventListener( orig, handler, true );\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 type, origFn;\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\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\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 * Sizzle CSS Selector Engine\n * Copyright 2012 jQuery Foundation and other contributors\n * Released under the MIT license\n * http://sizzlejs.com/\n */\n(function( window, undefined ) {\n\nvar i,\n\tcachedruns,\n\tExpr,\n\tgetText,\n\tisXML,\n\tcompile,\n\thasDuplicate,\n\toutermostContext,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsXML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\tsortOrder,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + -(new Date()),\n\tpreferredDoc = window.document,\n\tsupport = {},\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\n\t// General-purpose constants\n\tstrundefined = typeof undefined,\n\tMAX_NEGATIVE = 1 << 31,\n\n\t// Array methods\n\tarr = [],\n\tpop = arr.pop,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf if we can't use a native one\n\tindexOf = arr.indexOf || function( elem ) {\n\t\tvar i = 0,\n\t\t\tlen = this.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( this[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\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// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors\n\toperators = \"([*^$|!~]?=)\",\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + characterEncoding + \")\" + whitespace +\n\t\t\"*(?:\" + operators + whitespace + \"*(?:(['\\\"])((?:\\\\\\\\.|[^\\\\\\\\])*?)\\\\3|(\" + identifier + \")|)|)\" + whitespace + \"*\\\\]\",\n\n\t// Prefer arguments quoted,\n\t//   then not containing pseudos/brackets,\n\t//   then attribute selectors/non-parenthetical expressions,\n\t//   then anything else\n\t// These preferences are here to reduce the number of selectors\n\t//   needing tokenize in the PSEUDO preFilter\n\tpseudos = \":(\" + characterEncoding + \")(?:\\\\(((['\\\"])((?:\\\\\\\\.|[^\\\\\\\\])*?)\\\\3|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes.replace( 3, 8 ) + \")*)|.*)\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([\\\\x20\\\\t\\\\r\\\\n\\\\f>+~])\" + whitespace + \"*\" ),\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\"NAME\": new RegExp( \"^\\\\[name=['\\\"]?(\" + 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// 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\trsibling = /[\\x20\\t\\r\\n\\f]*[+~]/,\n\n\trnative = /^[^{]+\\{\\s*\\[native code/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trescape = /'|\\\\/g,\n\trattributeQuotes = /\\=[\\x20\\t\\r\\n\\f]*([^'\"\\]]*)[\\x20\\t\\r\\n\\f]*\\]/g,\n\n\t// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = /\\\\([\\da-fA-F]{1,6}[\\x20\\t\\r\\n\\f]?|.)/g,\n\tfunescape = function( _, escaped ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\treturn high !== high ?\n\t\t\tescaped :\n\t\t\t// BMP codepoint\n\t\t\thigh < 0 ?\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// Use a stripped-down slice if we can't use a native one\ntry {\n\tslice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType;\n} catch ( e ) {\n\tslice = function( i ) {\n\t\tvar elem,\n\t\t\tresults = [];\n\t\twhile ( (elem = this[i++]) ) {\n\t\t\tresults.push( elem );\n\t\t}\n\t\treturn results;\n\t};\n}\n\n/**\n * For feature detection\n * @param {Function} fn The function to test for native support\n */\nfunction isNative( fn ) {\n\treturn rnative.test( fn + \"\" );\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 cache,\n\t\tkeys = [];\n\n\treturn (cache = function( 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}\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// release memory in IE\n\t\tdiv = null;\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\n\tif ( !selector || typeof selector !== \"string\" ) {\n\t\treturn results;\n\t}\n\n\tif ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {\n\t\treturn [];\n\t}\n\n\tif ( !documentIsXML && !seed ) {\n\n\t\t// Shortcuts\n\t\tif ( (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 #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, slice.call(context.getElementsByTagName( selector ), 0) );\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.getByClassName && context.getElementsByClassName ) {\n\t\t\t\tpush.apply( results, slice.call(context.getElementsByClassName( m ), 0) );\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.test(selector) ) {\n\t\t\told = true;\n\t\t\tnid = expando;\n\t\t\tnewContext = context;\n\t\t\tnewSelector = nodeType === 9 && 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 ) && 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, slice.call( newContext.querySelectorAll(\n\t\t\t\t\t\tnewSelector\n\t\t\t\t\t), 0 ) );\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 * Detect xml\n * @param {Element|Object} elem An element or a document\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 doc = 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\n\t// Support tests\n\tdocumentIsXML = isXML( doc );\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.tagNameNoComments = assert(function( div ) {\n\t\tdiv.appendChild( doc.createComment(\"\") );\n\t\treturn !div.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Check if attributes should be retrieved by attribute nodes\n\tsupport.attributes = assert(function( div ) {\n\t\tdiv.innerHTML = \"<select></select>\";\n\t\tvar type = typeof div.lastChild.getAttribute(\"multiple\");\n\t\t// IE8 returns a string for some attributes even when not present\n\t\treturn type !== \"boolean\" && type !== \"string\";\n\t});\n\n\t// Check if getElementsByClassName can be trusted\n\tsupport.getByClassName = assert(function( div ) {\n\t\t// Opera can't find a second classname (in 9.6)\n\t\tdiv.innerHTML = \"<div class='hidden e'></div><div class='hidden'></div>\";\n\t\tif ( !div.getElementsByClassName || !div.getElementsByClassName(\"e\").length ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Safari 3.2 caches class attributes and doesn't catch changes\n\t\tdiv.lastChild.className = \"e\";\n\t\treturn div.getElementsByClassName(\"e\").length === 2;\n\t});\n\n\t// Check if getElementById returns elements by name\n\t// Check if getElementsByName privileges form controls or returns elements by ID\n\tsupport.getByName = assert(function( div ) {\n\t\t// Inject content\n\t\tdiv.id = expando + 0;\n\t\tdiv.innerHTML = \"<a name='\" + expando + \"'></a><div name='\" + expando + \"'></div>\";\n\t\tdocElem.insertBefore( div, docElem.firstChild );\n\n\t\t// Test\n\t\tvar pass = doc.getElementsByName &&\n\t\t\t// buggy browsers will return fewer than the correct 2\n\t\t\tdoc.getElementsByName( expando ).length === 2 +\n\t\t\t// buggy browsers will return more than the correct 0\n\t\t\tdoc.getElementsByName( expando + 0 ).length;\n\t\tsupport.getIdNotName = !doc.getElementById( expando );\n\n\t\t// Cleanup\n\t\tdocElem.removeChild( div );\n\n\t\treturn pass;\n\t});\n\n\t// IE6/7 return modified attributes\n\tExpr.attrHandle = assert(function( div ) {\n\t\tdiv.innerHTML = \"<a href='#'></a>\";\n\t\treturn div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&\n\t\t\tdiv.firstChild.getAttribute(\"href\") === \"#\";\n\t}) ?\n\t\t{} :\n\t\t{\n\t\t\t\"href\": function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"href\", 2 );\n\t\t\t},\n\t\t\t\"type\": function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"type\");\n\t\t\t}\n\t\t};\n\n\t// ID find and filter\n\tif ( support.getIdNotName ) {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== strundefined && !documentIsXML ) {\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\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== strundefined && !documentIsXML ) {\n\t\t\t\tvar m = context.getElementById( id );\n\n\t\t\t\treturn m ?\n\t\t\t\t\tm.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode(\"id\").value === id ?\n\t\t\t\t\t\t[m] :\n\t\t\t\t\t\tundefined :\n\t\t\t\t\t[];\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\tvar node = typeof elem.getAttributeNode !== strundefined && 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.tagNameNoComments ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== strundefined ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\t\t\t}\n\t\t} :\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\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// Name\n\tExpr.find[\"NAME\"] = support.getByName && function( tag, context ) {\n\t\tif ( typeof context.getElementsByName !== strundefined ) {\n\t\t\treturn context.getElementsByName( name );\n\t\t}\n\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\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// no need to also add to buggyMatches since matches checks buggyQSA\n\t// A support test would require too much code (would include document ready)\n\trbuggyQSA = [ \":focus\" ];\n\n\tif ( (support.qsa = isNative(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 explictly\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\tdiv.innerHTML = \"<select><option selected=''></option></select>\";\n\n\t\t\t// IE8 - Some boolean attributes are not treated correctly\n\t\t\tif ( !div.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:checked|disabled|ismap|multiple|readonly|selected|value)\" );\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\t\t});\n\n\t\tassert(function( div ) {\n\n\t\t\t// Opera 10-12/IE8 - ^= $= *= and empty values\n\t\t\t// Should not select anything\n\t\t\tdiv.innerHTML = \"<input type='hidden' i=''/>\";\n\t\t\tif ( div.querySelectorAll(\"[i^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + 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 = isNative( (matches = docElem.matchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.webkitMatchesSelector ||\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 = new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = new RegExp( rbuggyMatches.join(\"|\") );\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 = isNative(docElem.contains) || docElem.compareDocumentPosition ?\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// Document order sorting\n\tsortOrder = docElem.compareDocumentPosition ?\n\tfunction( a, b ) {\n\t\tvar compare;\n\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tif ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {\n\t\t\tif ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {\n\t\t\t\tif ( a === doc || contains( preferredDoc, a ) ) {\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\tif ( b === doc || contains( preferredDoc, b ) ) {\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\treturn compare & 4 ? -1 : 1;\n\t\t}\n\n\t\treturn a.compareDocumentPosition ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\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// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\t} else if ( !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\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\t// Always assume the presence of duplicates if sort doesn't\n\t// pass them to our comparison function (as in Google Chrome).\n\thasDuplicate = false;\n\t[0, 0].sort( sortOrder );\n\tsupport.detectDuplicates = hasDuplicate;\n\n\treturn document;\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\t// rbuggyQSA always contains :focus, so no need for an existence check\n\tif ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) {\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\tvar val;\n\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tif ( !documentIsXML ) {\n\t\tname = name.toLowerCase();\n\t}\n\tif ( (val = Expr.attrHandle[ name ]) ) {\n\t\treturn val( elem );\n\t}\n\tif ( documentIsXML || support.attributes ) {\n\t\treturn elem.getAttribute( name );\n\t}\n\treturn ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?\n\t\tname :\n\t\tval && val.specified ? val.value : null;\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n// Document sorting and removing duplicates\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\ti = 1,\n\t\tj = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\tfor ( ; (elem = results[i]); i++ ) {\n\t\t\tif ( elem === results[ i - 1 ] ) {\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\treturn results;\n};\n\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~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// Returns a function to use in pseudos for input types\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// Returns a function to use in pseudos for buttons\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// Returns a function to use in pseudos for positionals\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 * 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\tfor ( ; (node = elem[i]); 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 (see #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\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[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[5] && 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[4] ) {\n\t\t\t\tmatch[2] = match[4];\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( nodeName ) {\n\t\t\tif ( nodeName === \"*\" ) {\n\t\t\t\treturn function() { return true; };\n\t\t\t}\n\n\t\t\tnodeName = nodeName.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\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( elem.className || (typeof elem.getAttribute !== strundefined && 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 + \" \" ).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.call( 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\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\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 identifider\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 = documentIsXML ?\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\") :\n\t\t\t\t\t\telem.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 only affected by element nodes and content nodes(including text(3), cdata(4)),\n\t\t\t//   not comment, processing instructions, or others\n\t\t\t// Thanks to Diego Perini for the nodeName shortcut\n\t\t\t//   Greater than \"@\" means alpha characters (specifically not starting with \"#\" or \"?\")\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeName > \"@\" || elem.nodeType === 3 || elem.nodeType === 4 ) {\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\t// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)\n\t\t\t// use getAttribute instead to test this case\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === elem.type );\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\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\nfunction tokenize( 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 data, cache, outerCache,\n\t\t\t\tdirkey = 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 ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {\n\t\t\t\t\t\t\tif ( (data = cache[1]) === true || data === cachedruns ) {\n\t\t\t\t\t\t\t\treturn data === true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcache = outerCache[ dir ] = [ dirkey ];\n\t\t\t\t\t\t\tcache[1] = matcher( elem, context, xml ) || cachedruns;\n\t\t\t\t\t\t\tif ( cache[1] === true ) {\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 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.call( 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.call( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\treturn ( !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} ];\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( tokens.slice( 0, i - 1 ) ).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\t// A counter to specify which element is currently being matched\n\tvar matcherCachedRuns = 0,\n\t\tbySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, expandContext ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tsetMatched = [],\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\toutermost = expandContext != null,\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", expandContext && context.parentNode || context ),\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\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context !== document && context;\n\t\t\t\tcachedruns = matcherCachedRuns;\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\tfor ( ; (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\tcachedruns = ++matcherCachedRuns;\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, group /* 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 ( !group ) {\n\t\t\tgroup = tokenize( selector );\n\t\t}\n\t\ti = group.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( group[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\t}\n\treturn cached;\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 select( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tmatch = tokenize( selector );\n\n\tif ( !seed ) {\n\t\t// Try to minimize operations if there is only one group\n\t\tif ( match.length === 1 ) {\n\n\t\t\t// Take a shortcut and set the context if the root selector is an ID\n\t\t\ttokens = match[0] = match[0].slice( 0 );\n\t\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\t\tcontext.nodeType === 9 && !documentIsXML &&\n\t\t\t\t\tExpr.relative[ tokens[1].type ] ) {\n\n\t\t\t\tcontext = Expr.find[\"ID\"]( token.matches[0].replace( runescape, funescape ), context )[0];\n\t\t\t\tif ( !context ) {\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\n\t\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t\t}\n\n\t\t\t// Fetch a seed set for right-to-left matching\n\t\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\ttoken = tokens[i];\n\n\t\t\t\t// Abort if we hit a combinator\n\t\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\t\tif ( (seed = find(\n\t\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\t\trsibling.test( tokens[0].type ) && context.parentNode || context\n\t\t\t\t\t)) ) {\n\n\t\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\t\tpush.apply( results, slice.call( seed, 0 ) );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\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\t}\n\n\t// Compile and execute a filtering function\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\tcompile( selector, match )(\n\t\tseed,\n\t\tcontext,\n\t\tdocumentIsXML,\n\t\tresults,\n\t\trsibling.test( selector )\n\t);\n\treturn results;\n}\n\n// Deprecated\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nExpr.filters = setFilters.prototype = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\n// Initialize with the default document\nsetDocument();\n\n// Override sizzle attribute retrieval\nSizzle.attr = jQuery.attr;\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})( window );\nvar runtil = /Until$/,\n\trparentsprev = /^(?:parents|prev(?:Until|All))/,\n\tisSimple = /^.[^:#\\[\\.,]*$/,\n\trneedsContext = jQuery.expr.match.needsContext,\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.fn.extend({\n\tfind: function( selector ) {\n\t\tvar i, ret, self,\n\t\t\tlen = this.length;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\tself = this;\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\tret = [];\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, this[ 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;\n\t\treturn ret;\n\t},\n\n\thas: function( target ) {\n\t\tvar i,\n\t\t\ttargets = jQuery( target, this ),\n\t\t\tlen = targets.length;\n\n\t\treturn this.filter(function() {\n\t\t\tfor ( i = 0; i < len; 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\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, false) );\n\t},\n\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, true) );\n\t},\n\n\tis: function( selector ) {\n\t\treturn !!selector && (\n\t\t\ttypeof selector === \"string\" ?\n\t\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\t\trneedsContext.test( selector ) ?\n\t\t\t\t\tjQuery( selector, this.context ).index( this[0] ) >= 0 :\n\t\t\t\t\tjQuery.filter( selector, this ).length > 0 :\n\t\t\t\tthis.filter( selector ).length > 0 );\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\tret = [],\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\tcur = this[i];\n\n\t\t\twhile ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {\n\t\t\t\tif ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {\n\t\t\t\t\tret.push( cur );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );\n\t},\n\n\t// Determine the position of an element within\n\t// the matched set of elements\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 jQuery.inArray( this[0], jQuery( elem ) );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn jQuery.inArray(\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[0] : elem, this );\n\t},\n\n\tadd: function( selector, context ) {\n\t\tvar set = typeof selector === \"string\" ?\n\t\t\t\tjQuery( selector, context ) :\n\t\t\t\tjQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),\n\t\t\tall = jQuery.merge( this.get(), set );\n\n\t\treturn this.pushStack( jQuery.unique(all) );\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\njQuery.fn.andSelf = jQuery.fn.addBack;\n\nfunction sibling( cur, dir ) {\n\tdo {\n\t\tcur = cur[ dir ];\n\t} while ( cur && cur.nodeType !== 1 );\n\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 jQuery.nodeName( elem, \"iframe\" ) ?\n\t\t\telem.contentDocument || elem.contentWindow.document :\n\t\t\tjQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar ret = jQuery.map( this, fn, until );\n\n\t\tif ( !runtil.test( name ) ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tret = jQuery.filter( selector, ret );\n\t\t}\n\n\t\tret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;\n\n\t\tif ( this.length > 1 && rparentsprev.test( name ) ) {\n\t\t\tret = ret.reverse();\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\n\njQuery.extend({\n\tfilter: function( expr, elems, not ) {\n\t\tif ( not ) {\n\t\t\texpr = \":not(\" + expr + \")\";\n\t\t}\n\n\t\treturn elems.length === 1 ?\n\t\t\tjQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :\n\t\t\tjQuery.find.matches(expr, elems);\n\t},\n\n\tdir: function( elem, dir, until ) {\n\t\tvar matched = [],\n\t\t\tcur = elem[ dir ];\n\n\t\twhile ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {\n\t\t\tif ( cur.nodeType === 1 ) {\n\t\t\t\tmatched.push( cur );\n\t\t\t}\n\t\t\tcur = cur[dir];\n\t\t}\n\t\treturn matched;\n\t},\n\n\tsibling: function( n, elem ) {\n\t\tvar r = [];\n\n\t\tfor ( ; n; n = n.nextSibling ) {\n\t\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\t\tr.push( n );\n\t\t\t}\n\t\t}\n\n\t\treturn r;\n\t}\n});\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, keep ) {\n\n\t// Can't pass null or undefined to indexOf in Firefox 4\n\t// Set to 0 to skip string check\n\tqualifier = qualifier || 0;\n\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep(elements, function( elem, i ) {\n\t\t\tvar retVal = !!qualifier.call( elem, i, elem );\n\t\t\treturn retVal === keep;\n\t\t});\n\n\t} else if ( qualifier.nodeType ) {\n\t\treturn jQuery.grep(elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) === keep;\n\t\t});\n\n\t} else if ( typeof qualifier === \"string\" ) {\n\t\tvar filtered = jQuery.grep(elements, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t});\n\n\t\tif ( isSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter(qualifier, filtered, !keep);\n\t\t} else {\n\t\t\tqualifier = jQuery.filter( qualifier, filtered );\n\t\t}\n\t}\n\n\treturn jQuery.grep(elements, function( elem ) {\n\t\treturn ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;\n\t});\n}\nfunction createSafeFragment( document ) {\n\tvar list = nodeNames.split( \"|\" ),\n\t\tsafeFrag = document.createDocumentFragment();\n\n\tif ( safeFrag.createElement ) {\n\t\twhile ( list.length ) {\n\t\t\tsafeFrag.createElement(\n\t\t\t\tlist.pop()\n\t\t\t);\n\t\t}\n\t}\n\treturn safeFrag;\n}\n\nvar nodeNames = \"abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|\" +\n\t\t\"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video\",\n\trinlinejQuery = / jQuery\\d+=\"(?:null|\\d+)\"/g,\n\trnoshimcache = new RegExp(\"<(?:\" + nodeNames + \")[\\\\s/>]\", \"i\"),\n\trleadingWhitespace = /^\\s+/,\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,\n\trtagName = /<([\\w:]+)/,\n\trtbody = /<tbody/i,\n\trhtml = /<|&#?\\w+;/,\n\trnoInnerhtml = /<(?:script|style|link)/i,\n\tmanipulation_rcheckableType = /^(?:checkbox|radio)$/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\t\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\t\tlegend: [ 1, \"<fieldset>\", \"</fieldset>\" ],\n\t\tarea: [ 1, \"<map>\", \"</map>\" ],\n\t\tparam: [ 1, \"<object>\", \"</object>\" ],\n\t\tthead: [ 1, \"<table>\", \"</table>\" ],\n\t\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\t\tcol: [ 2, \"<table><tbody></tbody><colgroup>\", \"</colgroup></table>\" ],\n\t\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t\t// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,\n\t\t// unless wrapped in a div with non-breaking characters in front of it.\n\t\t_default: jQuery.support.htmlSerialize ? [ 0, \"\", \"\" ] : [ 1, \"X<div>\", \"</div>\"  ]\n\t},\n\tsafeFragment = createSafeFragment( document ),\n\tfragmentDiv = safeFragment.appendChild( document.createElement(\"div\") );\n\nwrapMap.optgroup = wrapMap.option;\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\njQuery.fn.extend({\n\ttext: function( value ) {\n\t\treturn jQuery.access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );\n\t\t}, null, value, arguments.length );\n\t},\n\n\twrapAll: function( html ) {\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\t\t\t// The elements to wrap the target around\n\t\t\tvar wrap = 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.firstChild && elem.firstChild.nodeType === 1 ) {\n\t\t\t\t\telem = elem.firstChild;\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\tappend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tthis.appendChild( elem );\n\t\t\t}\n\t\t});\n\t},\n\n\tprepend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tthis.insertBefore( elem, this.firstChild );\n\t\t\t}\n\t\t});\n\t},\n\n\tbefore: function() {\n\t\treturn this.domManip( arguments, false, 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, false, 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\t// keepData is for internal use only--do not document\n\tremove: function( selector, keepData ) {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = this[i]) != null; i++ ) {\n\t\t\tif ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {\n\t\t\t\tif ( !keepData && elem.nodeType === 1 ) {\n\t\t\t\t\tjQuery.cleanData( getAll( elem ) );\n\t\t\t\t}\n\n\t\t\t\tif ( elem.parentNode ) {\n\t\t\t\t\tif ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\t\t\tsetGlobalEval( getAll( elem, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t\telem.parentNode.removeChild( elem );\n\t\t\t\t}\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\t// Remove element nodes and prevent memory leaks\n\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t}\n\n\t\t\t// Remove any remaining nodes\n\t\t\twhile ( elem.firstChild ) {\n\t\t\t\telem.removeChild( elem.firstChild );\n\t\t\t}\n\n\t\t\t// If this is a select, ensure that it displays empty (#12336)\n\t\t\t// Support: IE<9\n\t\t\tif ( elem.options && jQuery.nodeName( elem, \"select\" ) ) {\n\t\t\t\telem.options.length = 0;\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 jQuery.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 ) {\n\t\t\t\treturn elem.nodeType === 1 ?\n\t\t\t\t\telem.innerHTML.replace( rinlinejQuery, \"\" ) :\n\t\t\t\t\tundefined;\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( jQuery.support.htmlSerialize || !rnoshimcache.test( value )  ) &&\n\t\t\t\t( jQuery.support.leadingWhitespace || !rleadingWhitespace.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\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\telem = this[i] || {};\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( value ) {\n\t\tvar isFunc = jQuery.isFunction( value );\n\n\t\t// Make sure that the elements are removed from the DOM before they are inserted\n\t\t// this can help fix replacing a parent with child elements\n\t\tif ( !isFunc && typeof value !== \"string\" ) {\n\t\t\tvalue = jQuery( value ).not( this ).detach();\n\t\t}\n\n\t\treturn this.domManip( [ value ], true, function( elem ) {\n\t\t\tvar next = this.nextSibling,\n\t\t\t\tparent = this.parentNode;\n\n\t\t\tif ( parent ) {\n\t\t\t\tjQuery( this ).remove();\n\t\t\t\tparent.insertBefore( elem, next );\n\t\t\t}\n\t\t});\n\t},\n\n\tdetach: function( selector ) {\n\t\treturn this.remove( selector, true );\n\t},\n\n\tdomManip: function( args, table, callback ) {\n\n\t\t// Flatten any nested arrays\n\t\targs = core_concat.apply( [], args );\n\n\t\tvar first, node, hasScripts,\n\t\t\tscripts, doc, fragment,\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 || !( l <= 1 || typeof value !== \"string\" || jQuery.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, table ? self.html() : undefined );\n\t\t\t\t}\n\t\t\t\tself.domManip( args, table, 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\ttable = table && jQuery.nodeName( first, \"tr\" );\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\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(\n\t\t\t\t\t\ttable && jQuery.nodeName( this[i], \"table\" ) ?\n\t\t\t\t\t\t\tfindOrAppend( this[i], \"tbody\" ) :\n\t\t\t\t\t\t\tthis[i],\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\ti\n\t\t\t\t\t);\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!jQuery._data( 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// Hope ajax is available...\n\t\t\t\t\t\t\t\tjQuery.ajax({\n\t\t\t\t\t\t\t\t\turl: node.src,\n\t\t\t\t\t\t\t\t\ttype: \"GET\",\n\t\t\t\t\t\t\t\t\tdataType: \"script\",\n\t\t\t\t\t\t\t\t\tasync: false,\n\t\t\t\t\t\t\t\t\tglobal: false,\n\t\t\t\t\t\t\t\t\t\"throws\": true\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.text || node.textContent || node.innerHTML || \"\" ).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\n\t\t\t\t// Fix #11809: Avoid leaking memory\n\t\t\t\tfragment = first = null;\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n});\n\nfunction findOrAppend( elem, tag ) {\n\treturn elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\tvar attr = elem.getAttributeNode(\"type\");\n\telem.type = ( attr && attr.specified ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tvar match = rscriptTypeMasked.exec( elem.type );\n\tif ( match ) {\n\t\telem.type = match[1];\n\t} else {\n\t\telem.removeAttribute(\"type\");\n\t}\n\treturn elem;\n}\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar elem,\n\t\ti = 0;\n\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\t\tjQuery._data( elem, \"globalEval\", !refElements || jQuery._data( refElements[i], \"globalEval\" ) );\n\t}\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\n\tif ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {\n\t\treturn;\n\t}\n\n\tvar type, i, l,\n\t\toldData = jQuery._data( src ),\n\t\tcurData = jQuery._data( dest, oldData ),\n\t\tevents = oldData.events;\n\n\tif ( events ) {\n\t\tdelete curData.handle;\n\t\tcurData.events = {};\n\n\t\tfor ( type in events ) {\n\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t// make the cloned public data object a copy from the original\n\tif ( curData.data ) {\n\t\tcurData.data = jQuery.extend( {}, curData.data );\n\t}\n}\n\nfunction fixCloneNodeIssues( src, dest ) {\n\tvar nodeName, e, data;\n\n\t// We do not need to do anything for non-Elements\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\tnodeName = dest.nodeName.toLowerCase();\n\n\t// IE6-8 copies events bound via attachEvent when using cloneNode.\n\tif ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {\n\t\tdata = jQuery._data( dest );\n\n\t\tfor ( e in data.events ) {\n\t\t\tjQuery.removeEvent( dest, e, data.handle );\n\t\t}\n\n\t\t// Event data gets referenced instead of copied if the expando gets copied too\n\t\tdest.removeAttribute( jQuery.expando );\n\t}\n\n\t// IE blanks contents when cloning scripts, and tries to evaluate newly-set text\n\tif ( nodeName === \"script\" && dest.text !== src.text ) {\n\t\tdisableScript( dest ).text = src.text;\n\t\trestoreScript( dest );\n\n\t// IE6-10 improperly clones children of object elements using classid.\n\t// IE10 throws NoModificationAllowedError if parent is null, #12132.\n\t} else if ( nodeName === \"object\" ) {\n\t\tif ( dest.parentNode ) {\n\t\t\tdest.outerHTML = src.outerHTML;\n\t\t}\n\n\t\t// This path appears unavoidable for IE9. When cloning an object\n\t\t// element in IE9, the outerHTML strategy above is not sufficient.\n\t\t// If the src has innerHTML and the destination does not,\n\t\t// copy the src.innerHTML into the dest.innerHTML. #10324\n\t\tif ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {\n\t\t\tdest.innerHTML = src.innerHTML;\n\t\t}\n\n\t} else if ( nodeName === \"input\" && manipulation_rcheckableType.test( src.type ) ) {\n\t\t// IE6-8 fails to persist the checked state of a cloned checkbox\n\t\t// or radio button. Worse, IE6-7 fail to give the cloned element\n\t\t// a checked appearance if the defaultChecked value isn't also set\n\n\t\tdest.defaultChecked = dest.checked = src.checked;\n\n\t\t// IE6-7 get confused and end up setting the value of a cloned\n\t\t// checkbox/radio button to an empty string instead of \"on\"\n\t\tif ( dest.value !== src.value ) {\n\t\t\tdest.value = src.value;\n\t\t}\n\n\t// IE6-8 fails to return the selected option to the default selected\n\t// state when cloning options\n\t} else if ( nodeName === \"option\" ) {\n\t\tdest.defaultSelected = dest.selected = src.defaultSelected;\n\n\t// IE6-8 fails to set the defaultValue to the correct value when\n\t// cloning other types of input fields\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\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\ti = 0,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1;\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// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()\n\t\t\tcore_push.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\n\nfunction getAll( context, tag ) {\n\tvar elems, elem,\n\t\ti = 0,\n\t\tfound = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || \"*\" ) :\n\t\t\ttypeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || \"*\" ) :\n\t\t\tundefined;\n\n\tif ( !found ) {\n\t\tfor ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( !tag || jQuery.nodeName( elem, tag ) ) {\n\t\t\t\tfound.push( elem );\n\t\t\t} else {\n\t\t\t\tjQuery.merge( found, getAll( elem, tag ) );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn tag === undefined || tag && jQuery.nodeName( context, tag ) ?\n\t\tjQuery.merge( [ context ], found ) :\n\t\tfound;\n}\n\n// Used in buildFragment, fixes the defaultChecked property\nfunction fixDefaultChecked( elem ) {\n\tif ( manipulation_rcheckableType.test( elem.type ) ) {\n\t\telem.defaultChecked = elem.checked;\n\t}\n}\n\njQuery.extend({\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar destElements, node, clone, i, srcElements,\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\tif ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( \"<\" + elem.nodeName + \">\" ) ) {\n\t\t\tclone = elem.cloneNode( true );\n\n\t\t// IE<=8 does not properly clone detached, unknown element nodes\n\t\t} else {\n\t\t\tfragmentDiv.innerHTML = elem.outerHTML;\n\t\t\tfragmentDiv.removeChild( clone = fragmentDiv.firstChild );\n\t\t}\n\n\t\tif ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&\n\t\t\t\t(elem.nodeType === 1 || elem.nodeType === 11) && !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\t// Fix all IE cloning issues\n\t\t\tfor ( i = 0; (node = srcElements[i]) != null; ++i ) {\n\t\t\t\t// Ensure that the destination node is not null; Fixes #9587\n\t\t\t\tif ( destElements[i] ) {\n\t\t\t\t\tfixCloneNodeIssues( node, destElements[i] );\n\t\t\t\t}\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; (node = srcElements[i]) != null; i++ ) {\n\t\t\t\t\tcloneCopyEvent( node, 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\tdestElements = srcElements = node = null;\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 j, elem, contains,\n\t\t\ttmp, tag, tbody, wrap,\n\t\t\tl = elems.length,\n\n\t\t\t// Ensure a safe fragment\n\t\t\tsafe = createSafeFragment( context ),\n\n\t\t\tnodes = [],\n\t\t\ti = 0;\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\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 || safe.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\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// Manually add leading whitespace removed by IE\n\t\t\t\t\tif ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {\n\t\t\t\t\t\tnodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove IE's autoinserted <tbody> from table fragments\n\t\t\t\t\tif ( !jQuery.support.tbody ) {\n\n\t\t\t\t\t\t// String was a <table>, *may* have spurious <tbody>\n\t\t\t\t\t\telem = tag === \"table\" && !rtbody.test( elem ) ?\n\t\t\t\t\t\t\ttmp.firstChild :\n\n\t\t\t\t\t\t\t// String was a bare <thead> or <tfoot>\n\t\t\t\t\t\t\twrap[1] === \"<table>\" && !rtbody.test( elem ) ?\n\t\t\t\t\t\t\t\ttmp :\n\t\t\t\t\t\t\t\t0;\n\n\t\t\t\t\t\tj = elem && elem.childNodes.length;\n\t\t\t\t\t\twhile ( j-- ) {\n\t\t\t\t\t\t\tif ( jQuery.nodeName( (tbody = elem.childNodes[j]), \"tbody\" ) && !tbody.childNodes.length ) {\n\t\t\t\t\t\t\t\telem.removeChild( tbody );\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\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t\t// Fix #12392 for WebKit and IE > 9\n\t\t\t\t\ttmp.textContent = \"\";\n\n\t\t\t\t\t// Fix #12392 for oldIE\n\t\t\t\t\twhile ( tmp.firstChild ) {\n\t\t\t\t\t\ttmp.removeChild( tmp.firstChild );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remember the top-level container for proper cleanup\n\t\t\t\t\ttmp = safe.lastChild;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Fix #11356: Clear elements from fragment\n\t\tif ( tmp ) {\n\t\t\tsafe.removeChild( tmp );\n\t\t}\n\n\t\t// Reset defaultChecked for any radios and checkboxes\n\t\t// about to be appended to the DOM in IE 6/7 (#8060)\n\t\tif ( !jQuery.support.appendChecked ) {\n\t\t\tjQuery.grep( getAll( nodes, \"input\" ), fixDefaultChecked );\n\t\t}\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( safe.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\ttmp = null;\n\n\t\treturn safe;\n\t},\n\n\tcleanData: function( elems, /* internal */ acceptData ) {\n\t\tvar elem, type, id, data,\n\t\t\ti = 0,\n\t\t\tinternalKey = jQuery.expando,\n\t\t\tcache = jQuery.cache,\n\t\t\tdeleteExpando = jQuery.support.deleteExpando,\n\t\t\tspecial = jQuery.event.special;\n\n\t\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\n\t\t\tif ( acceptData || jQuery.acceptData( elem ) ) {\n\n\t\t\t\tid = elem[ internalKey ];\n\t\t\t\tdata = id && cache[ id ];\n\n\t\t\t\tif ( data ) {\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\n\t\t\t\t\t// Remove cache only if it was not already removed by jQuery.event.remove\n\t\t\t\t\tif ( cache[ id ] ) {\n\n\t\t\t\t\t\tdelete cache[ id ];\n\n\t\t\t\t\t\t// IE does not allow us to delete expando properties from nodes,\n\t\t\t\t\t\t// nor does it have a removeAttribute function on Document nodes;\n\t\t\t\t\t\t// we must handle all of these cases\n\t\t\t\t\t\tif ( deleteExpando ) {\n\t\t\t\t\t\t\tdelete elem[ internalKey ];\n\n\t\t\t\t\t\t} else if ( typeof elem.removeAttribute !== core_strundefined ) {\n\t\t\t\t\t\t\telem.removeAttribute( internalKey );\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\telem[ internalKey ] = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcore_deletedIds.push( id );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n});\nvar iframe, getStyles, curCSS,\n\tralpha = /alpha\\([^)]*\\)/i,\n\tropacity = /opacity\\s*=\\s*([^)]*)/,\n\trposition = /^(top|right|bottom|left)$/,\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\trmargin = /^margin/,\n\trnumsplit = new RegExp( \"^(\" + core_pnum + \")(.*)$\", \"i\" ),\n\trnumnonpx = new RegExp( \"^(\" + core_pnum + \")(?!px)[a-z%]+$\", \"i\" ),\n\trrelNum = new RegExp( \"^([+-])=(\" + core_pnum + \")\", \"i\" ),\n\telemdisplay = { BODY: \"block\" },\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: 0,\n\t\tfontWeight: 400\n\t},\n\n\tcssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ],\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.charAt(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 isHidden( elem, el ) {\n\t// isHidden might be called from jQuery#filter function;\n\t// in that case, element will be second argument\n\telem = el || elem;\n\treturn jQuery.css( elem, \"display\" ) === \"none\" || !jQuery.contains( elem.ownerDocument, elem );\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 ] = jQuery._data( 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 ] = jQuery._data( elem, \"olddisplay\", css_defaultDisplay(elem.nodeName) );\n\t\t\t}\n\t\t} else {\n\n\t\t\tif ( !values[ index ] ) {\n\t\t\t\thidden = isHidden( elem );\n\n\t\t\t\tif ( display && display !== \"none\" || !hidden ) {\n\t\t\t\t\tjQuery._data( elem, \"olddisplay\", hidden ? display : jQuery.css( elem, \"display\" ) );\n\t\t\t\t}\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.fn.extend({\n\tcss: function( name, value ) {\n\t\treturn jQuery.access( this, function( elem, name, value ) {\n\t\t\tvar len, styles,\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\tvar bool = typeof state === \"boolean\";\n\n\t\treturn this.each(function() {\n\t\t\tif ( bool ? state : 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\njQuery.extend({\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\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// Exclude the following css properties to add px\n\tcssNumber: {\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": 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// normalize float css property\n\t\t\"float\": jQuery.support.cssFloat ? \"cssFloat\" : \"styleFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\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\n\t\t// followed by the 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 relative number strings (+= 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 NaN and null values aren't set. See: #7116\n\t\t\tif ( value == null || type === \"number\" && isNaN( value ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, 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// Fixes #8908, it can be done more correctly by specifing setters in cssHooks,\n\t\t\t// but it would mean to define eight (for every problematic property) identical functions\n\t\t\tif ( !jQuery.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\n\t\t\t\t// Wrapped to prevent IE from throwing errors when 'invalid' values are provided\n\t\t\t\t// Fixes bug #5509\n\t\t\t\ttry {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t} catch(e) {}\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 num, val, 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// gets hook for the prefixed version\n\t\t// followed by the unprefixed version\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// Return, converting to number 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\t// A method for quickly swapping in/out CSS properties to get correct calculations\n\tswap: function( elem, options, callback, args ) {\n\t\tvar ret, name,\n\t\t\told = {};\n\n\t\t// Remember the old values, and insert the new ones\n\t\tfor ( name in options ) {\n\t\t\told[ name ] = elem.style[ name ];\n\t\t\telem.style[ name ] = options[ name ];\n\t\t}\n\n\t\tret = callback.apply( elem, args || [] );\n\n\t\t// Revert the old values\n\t\tfor ( name in options ) {\n\t\t\telem.style[ name ] = old[ name ];\n\t\t}\n\n\t\treturn ret;\n\t}\n});\n\n// NOTE: we've included the \"window\" in window.getComputedStyle\n// because jsdom on node.js will break without it.\nif ( window.getComputedStyle ) {\n\tgetStyles = function( elem ) {\n\t\treturn window.getComputedStyle( elem, null );\n\t};\n\n\tcurCSS = function( elem, name, _computed ) {\n\t\tvar width, minWidth, maxWidth,\n\t\t\tcomputed = _computed || getStyles( elem ),\n\n\t\t\t// getPropertyValue is only needed for .css('filter') in IE9, see #12537\n\t\t\tret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,\n\t\t\tstyle = elem.style;\n\n\t\tif ( computed ) {\n\n\t\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\tret = jQuery.style( elem, name );\n\t\t\t}\n\n\t\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t\t// Chrome < 17 and Safari 5.0 uses \"computed value\" instead of \"used value\" for margin-right\n\t\t\t// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels\n\t\t\t// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values\n\t\t\tif ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n\t\t\t\t// Remember the original values\n\t\t\t\twidth = style.width;\n\t\t\t\tminWidth = style.minWidth;\n\t\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t\t// Put in the new values to get a computed value out\n\t\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\t\tret = computed.width;\n\n\t\t\t\t// Revert the changed values\n\t\t\t\tstyle.width = width;\n\t\t\t\tstyle.minWidth = minWidth;\n\t\t\t\tstyle.maxWidth = maxWidth;\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t};\n} else if ( document.documentElement.currentStyle ) {\n\tgetStyles = function( elem ) {\n\t\treturn elem.currentStyle;\n\t};\n\n\tcurCSS = function( elem, name, _computed ) {\n\t\tvar left, rs, rsLeft,\n\t\t\tcomputed = _computed || getStyles( elem ),\n\t\t\tret = computed ? computed[ name ] : undefined,\n\t\t\tstyle = elem.style;\n\n\t\t// Avoid setting ret to empty string here\n\t\t// so we don't default to auto\n\t\tif ( ret == null && style && style[ name ] ) {\n\t\t\tret = style[ name ];\n\t\t}\n\n\t\t// From the awesome hack by Dean Edwards\n\t\t// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291\n\n\t\t// If we're not dealing with a regular pixel number\n\t\t// but a number that has a weird ending, we need to convert it to pixels\n\t\t// but not position css attributes, as those are proportional to the parent element instead\n\t\t// and we can't measure the parent instead because it might trigger a \"stacking dolls\" problem\n\t\tif ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\tleft = style.left;\n\t\t\trs = elem.runtimeStyle;\n\t\t\trsLeft = rs && rs.left;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tif ( rsLeft ) {\n\t\t\t\trs.left = elem.currentStyle.left;\n\t\t\t}\n\t\t\tstyle.left = name === \"fontSize\" ? \"1em\" : ret;\n\t\t\tret = style.pixelLeft + \"px\";\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.left = left;\n\t\t\tif ( rsLeft ) {\n\t\t\t\trs.left = rsLeft;\n\t\t\t}\n\t\t}\n\n\t\treturn ret === \"\" ? \"auto\" : ret;\n\t};\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.support.boxSizing && 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// we need the 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 && ( jQuery.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\n// Try to determine the default display value of an element\nfunction css_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\t\t\t// Use the already-created iframe if possible\n\t\t\tiframe = ( iframe ||\n\t\t\t\tjQuery(\"<iframe frameborder='0' width='0' height='0'/>\")\n\t\t\t\t.css( \"cssText\", \"display:block !important\" )\n\t\t\t).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].contentWindow || iframe[0].contentDocument ).document;\n\t\t\tdoc.write(\"<!doctype html><html><body>\");\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}\n\n// Called ONLY from within css_defaultDisplay\nfunction actualDisplay( name, doc ) {\n\tvar elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),\n\t\tdisplay = jQuery.css( elem[0], \"display\" );\n\telem.remove();\n\treturn display;\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\t\t\t\t// certain elements can have dimension info if we invisibly show them\n\t\t\t\t// however, it must have a current display style that would benefit from this\n\t\t\t\treturn elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, \"display\" ) ) ?\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.support.boxSizing && jQuery.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\nif ( !jQuery.support.opacity ) {\n\tjQuery.cssHooks.opacity = {\n\t\tget: function( elem, computed ) {\n\t\t\t// IE uses filters for opacity\n\t\t\treturn ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || \"\" ) ?\n\t\t\t\t( 0.01 * parseFloat( RegExp.$1 ) ) + \"\" :\n\t\t\t\tcomputed ? \"1\" : \"\";\n\t\t},\n\n\t\tset: function( elem, value ) {\n\t\t\tvar style = elem.style,\n\t\t\t\tcurrentStyle = elem.currentStyle,\n\t\t\t\topacity = jQuery.isNumeric( value ) ? \"alpha(opacity=\" + value * 100 + \")\" : \"\",\n\t\t\t\tfilter = currentStyle && currentStyle.filter || style.filter || \"\";\n\n\t\t\t// IE has trouble with opacity if it does not have layout\n\t\t\t// Force it by setting the zoom level\n\t\t\tstyle.zoom = 1;\n\n\t\t\t// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652\n\t\t\t// if value === \"\", then remove inline opacity #12685\n\t\t\tif ( ( value >= 1 || value === \"\" ) &&\n\t\t\t\t\tjQuery.trim( filter.replace( ralpha, \"\" ) ) === \"\" &&\n\t\t\t\t\tstyle.removeAttribute ) {\n\n\t\t\t\t// Setting style.filter to null, \"\" & \" \" still leave \"filter:\" in the cssText\n\t\t\t\t// if \"filter:\" is present at all, clearType is disabled, we want to avoid this\n\t\t\t\t// style.removeAttribute is IE Only, but so apparently is this code path...\n\t\t\t\tstyle.removeAttribute( \"filter\" );\n\n\t\t\t\t// if there is no filter style applied in a css rule or unset inline opacity, we are done\n\t\t\t\tif ( value === \"\" || currentStyle && !currentStyle.filter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// otherwise, set new filter values\n\t\t\tstyle.filter = ralpha.test( filter ) ?\n\t\t\t\tfilter.replace( ralpha, opacity ) :\n\t\t\t\tfilter + \" \" + opacity;\n\t\t}\n\t};\n}\n\n// These hooks cannot be added until DOM ready because the support test\n// for it is not run until after DOM ready\njQuery(function() {\n\tif ( !jQuery.support.reliableMarginRight ) {\n\t\tjQuery.cssHooks.marginRight = {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\t\t\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t\t\t// Work around by temporarily setting element display to inline-block\n\t\t\t\t\treturn jQuery.swap( elem, { \"display\": \"inline-block\" },\n\t\t\t\t\t\tcurCSS, [ elem, \"marginRight\" ] );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n\t// getComputedStyle returns percent when specified for top/left/bottom/right\n\t// rather than make the css module depend on the offset module, we just check for it here\n\tif ( !jQuery.support.pixelPosition && jQuery.fn.position ) {\n\t\tjQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\t\t\tjQuery.cssHooks[ prop ] = {\n\t\t\t\tget: function( elem, computed ) {\n\t\t\t\t\tif ( computed ) {\n\t\t\t\t\t\tcomputed = curCSS( elem, prop );\n\t\t\t\t\t\t// if curCSS returns percentage, fallback to offset\n\t\t\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\t\t\tcomputed;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t});\n\t}\n\n});\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.hidden = function( elem ) {\n\t\t// Support: Opera <= 12.12\n\t\t// Opera reports offsetWidths and offsetHeights less than zero on some elements\n\t\treturn elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||\n\t\t\t(!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, \"display\" )) === \"none\");\n\t};\n\n\tjQuery.expr.filters.visible = function( elem ) {\n\t\treturn !jQuery.expr.filters.hidden( elem );\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});\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\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\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 || !manipulation_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//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\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}\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.hover = function( fnOver, fnOut ) {\n\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n};\nvar\n\t// Document location\n\tajaxLocParts,\n\tajaxLocation,\n\tajax_nonce = jQuery.now(),\n\n\tajax_rquery = /\\?/,\n\trhash = /#.*$/,\n\trts = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg, // IE leaves an \\r character at EOL\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// Keep a copy of the old load method\n\t_load = jQuery.fn.load,\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// #8138, IE may throw an exception when accessing\n// a field from window.location if document.domain has been set\ntry {\n\tajaxLocation = location.href;\n} catch( e ) {\n\t// Use the href attribute of an A element\n\t// since IE will modify it given document.location\n\tajaxLocation = document.createElement( \"a\" );\n\tajaxLocation.href = \"\";\n\tajaxLocation = ajaxLocation.href;\n}\n\n// Segment location into parts\najaxLocParts = 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( core_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 deep, key,\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\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, response, type,\n\t\tself = this,\n\t\toff = url.indexOf(\" \");\n\n\tif ( off >= 0 ) {\n\t\tselector = url.slice( off, url.length );\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// 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\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\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},\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\": window.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 // Cross-domain detection vars\n\t\t\tparts,\n\t\t\t// Loop variable\n\t\t\ti,\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\t\t\t// Response headers as string\n\t\t\tresponseHeadersString,\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\ttransport,\n\t\t\t// Response headers\n\t\t\tresponseHeaders,\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 (#5866: IE7 issue with protocol-less urls)\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, \"\" ).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( core_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\tfireGlobals = 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 += ( ajax_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_=\" + ajax_nonce++ ) :\n\n\t\t\t\t\t// Otherwise add one to the end\n\t\t\t\t\tcacheURL + ( ajax_rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ajax_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// 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// If successful, handle type chaining\n\t\t\tif ( status >= 200 && status < 300 || status === 304 ) {\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 ) {\n\t\t\t\t\tisSuccess = true;\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\tisSuccess = true;\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\tisSuccess = ajaxConvert( s, response );\n\t\t\t\t\tstatusText = isSuccess.state;\n\t\t\t\t\tsuccess = isSuccess.data;\n\t\t\t\t\terror = isSuccess.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// We extract error from statusText\n\t\t\t\t// then normalize statusText and status 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\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t}\n});\n\n/* Handles responses to an ajax request:\n * - sets all responseXXX fields accordingly\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\tvar firstDataType, ct, finalDataType, type,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes,\n\t\tresponseFields = s.responseFields;\n\n\t// Fill responseXXX fields\n\tfor ( type in responseFields ) {\n\t\tif ( type in responses ) {\n\t\t\tjqXHR[ responseFields[type] ] = responses[ type ];\n\t\t}\n\t}\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\nfunction ajaxConvert( s, response ) {\n\tvar conv2, current, conv, tmp,\n\t\tconverters = {},\n\t\ti = 0,\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\t\tprev = dataTypes[ 0 ];\n\n\t// Apply the dataFilter if provided\n\tif ( s.dataFilter ) {\n\t\tresponse = s.dataFilter( response, s.dataType );\n\t}\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\t// Convert to each sequential dataType, tolerating list modification\n\tfor ( ; (current = dataTypes[++i]); ) {\n\n\t\t// There's only work to do if current dataType is non-auto\n\t\tif ( current !== \"*\" ) {\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\tif ( 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.splice( i--, 0, current );\n\t\t\t\t\t\t\t\t}\n\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\n\t\t\t// Update prev for next iteration\n\t\t\tprev = current;\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\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 global\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\ts.global = false;\n\t}\n});\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function(s) {\n\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\n\t\tvar script,\n\t\t\thead = document.head || jQuery(\"head\")[0] || document.documentElement;\n\n\t\treturn {\n\n\t\t\tsend: function( _, callback ) {\n\n\t\t\t\tscript = document.createElement(\"script\");\n\n\t\t\t\tscript.async = true;\n\n\t\t\t\tif ( s.scriptCharset ) {\n\t\t\t\t\tscript.charset = s.scriptCharset;\n\t\t\t\t}\n\n\t\t\t\tscript.src = s.url;\n\n\t\t\t\t// Attach handlers for all browsers\n\t\t\t\tscript.onload = script.onreadystatechange = function( _, isAbort ) {\n\n\t\t\t\t\tif ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {\n\n\t\t\t\t\t\t// Handle memory leak in IE\n\t\t\t\t\t\tscript.onload = script.onreadystatechange = null;\n\n\t\t\t\t\t\t// Remove the script\n\t\t\t\t\t\tif ( script.parentNode ) {\n\t\t\t\t\t\t\tscript.parentNode.removeChild( script );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Dereference the script\n\t\t\t\t\t\tscript = null;\n\n\t\t\t\t\t\t// Callback if not abort\n\t\t\t\t\t\tif ( !isAbort ) {\n\t\t\t\t\t\t\tcallback( 200, \"success\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\thead.insertBefore( script, head.firstChild );\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( script ) {\n\t\t\t\t\tscript.onload( undefined, true );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\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 + \"_\" + ( ajax_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 += ( ajax_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});\nvar xhrCallbacks, xhrSupported,\n\txhrId = 0,\n\t// #5280: Internet Explorer will keep connections alive if we don't abort on unload\n\txhrOnUnloadAbort = window.ActiveXObject && function() {\n\t\t// Abort all pending requests\n\t\tvar key;\n\t\tfor ( key in xhrCallbacks ) {\n\t\t\txhrCallbacks[ key ]( undefined, true );\n\t\t}\n\t};\n\n// Functions to create xhrs\nfunction createStandardXHR() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch( e ) {}\n}\n\nfunction createActiveXHR() {\n\ttry {\n\t\treturn new window.ActiveXObject(\"Microsoft.XMLHTTP\");\n\t} catch( e ) {}\n}\n\n// Create the request object\n// (This is still attached to ajaxSettings for backward compatibility)\njQuery.ajaxSettings.xhr = window.ActiveXObject ?\n\t/* Microsoft failed to properly\n\t * implement the XMLHttpRequest in IE7 (can't request local files),\n\t * so we use the ActiveXObject when it is available\n\t * Additionally XMLHttpRequest can be disabled in IE7/IE8 so\n\t * we need a fallback.\n\t */\n\tfunction() {\n\t\treturn !this.isLocal && createStandardXHR() || createActiveXHR();\n\t} :\n\t// For all other browsers, use the standard XMLHttpRequest object\n\tcreateStandardXHR;\n\n// Determine support properties\nxhrSupported = jQuery.ajaxSettings.xhr();\njQuery.support.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nxhrSupported = jQuery.support.ajax = !!xhrSupported;\n\n// Create transport if the browser can provide an xhr\nif ( xhrSupported ) {\n\n\tjQuery.ajaxTransport(function( s ) {\n\t\t// Cross domain only allowed if supported through XMLHttpRequest\n\t\tif ( !s.crossDomain || jQuery.support.cors ) {\n\n\t\t\tvar callback;\n\n\t\t\treturn {\n\t\t\t\tsend: function( headers, complete ) {\n\n\t\t\t\t\t// Get a new xhr\n\t\t\t\t\tvar handle, i,\n\t\t\t\t\t\txhr = s.xhr();\n\n\t\t\t\t\t// Open the socket\n\t\t\t\t\t// Passing null username, generates a login popup on Opera (#2865)\n\t\t\t\t\tif ( s.username ) {\n\t\t\t\t\t\txhr.open( s.type, s.url, s.async, s.username, s.password );\n\t\t\t\t\t} else {\n\t\t\t\t\t\txhr.open( s.type, s.url, s.async );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply custom fields if provided\n\t\t\t\t\tif ( s.xhrFields ) {\n\t\t\t\t\t\tfor ( i in s.xhrFields ) {\n\t\t\t\t\t\t\txhr[ i ] = s.xhrFields[ i ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Override mime type if needed\n\t\t\t\t\tif ( s.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\t\txhr.overrideMimeType( s.mimeType );\n\t\t\t\t\t}\n\n\t\t\t\t\t// X-Requested-With header\n\t\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\t\tif ( !s.crossDomain && !headers[\"X-Requested-With\"] ) {\n\t\t\t\t\t\theaders[\"X-Requested-With\"] = \"XMLHttpRequest\";\n\t\t\t\t\t}\n\n\t\t\t\t\t// Need an extra try/catch for cross domain requests in Firefox 3\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch( err ) {}\n\n\t\t\t\t\t// Do send the request\n\t\t\t\t\t// This may raise an exception which is actually\n\t\t\t\t\t// handled in jQuery.ajax (so no try/catch here)\n\t\t\t\t\txhr.send( ( s.hasContent && s.data ) || null );\n\n\t\t\t\t\t// Listener\n\t\t\t\t\tcallback = function( _, isAbort ) {\n\t\t\t\t\t\tvar status, responseHeaders, statusText, responses;\n\n\t\t\t\t\t\t// Firefox throws exceptions when accessing properties\n\t\t\t\t\t\t// of an xhr when a network error occurred\n\t\t\t\t\t\t// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)\n\t\t\t\t\t\ttry {\n\n\t\t\t\t\t\t\t// Was never called and is aborted or complete\n\t\t\t\t\t\t\tif ( callback && ( isAbort || xhr.readyState === 4 ) ) {\n\n\t\t\t\t\t\t\t\t// Only called once\n\t\t\t\t\t\t\t\tcallback = undefined;\n\n\t\t\t\t\t\t\t\t// Do not keep as active anymore\n\t\t\t\t\t\t\t\tif ( handle ) {\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = jQuery.noop;\n\t\t\t\t\t\t\t\t\tif ( xhrOnUnloadAbort ) {\n\t\t\t\t\t\t\t\t\t\tdelete xhrCallbacks[ handle ];\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\t// If it's an abort\n\t\t\t\t\t\t\t\tif ( isAbort ) {\n\t\t\t\t\t\t\t\t\t// Abort it manually if needed\n\t\t\t\t\t\t\t\t\tif ( xhr.readyState !== 4 ) {\n\t\t\t\t\t\t\t\t\t\txhr.abort();\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\tresponses = {};\n\t\t\t\t\t\t\t\t\tstatus = xhr.status;\n\t\t\t\t\t\t\t\t\tresponseHeaders = xhr.getAllResponseHeaders();\n\n\t\t\t\t\t\t\t\t\t// When requesting binary data, IE6-9 will throw an exception\n\t\t\t\t\t\t\t\t\t// on any attempt to access responseText (#11426)\n\t\t\t\t\t\t\t\t\tif ( typeof xhr.responseText === \"string\" ) {\n\t\t\t\t\t\t\t\t\t\tresponses.text = xhr.responseText;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Firefox throws an exception when accessing\n\t\t\t\t\t\t\t\t\t// statusText for faulty cross-domain requests\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tstatusText = xhr.statusText;\n\t\t\t\t\t\t\t\t\t} catch( e ) {\n\t\t\t\t\t\t\t\t\t\t// We normalize with Webkit giving an empty statusText\n\t\t\t\t\t\t\t\t\t\tstatusText = \"\";\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Filter status for non standard behaviors\n\n\t\t\t\t\t\t\t\t\t// If the request is local and we have data: assume a success\n\t\t\t\t\t\t\t\t\t// (success with no data won't get notified, that's the best we\n\t\t\t\t\t\t\t\t\t// can do given current implementations)\n\t\t\t\t\t\t\t\t\tif ( !status && s.isLocal && !s.crossDomain ) {\n\t\t\t\t\t\t\t\t\t\tstatus = responses.text ? 200 : 404;\n\t\t\t\t\t\t\t\t\t// IE - #1450: sometimes returns 1223 when it should be 204\n\t\t\t\t\t\t\t\t\t} else if ( status === 1223 ) {\n\t\t\t\t\t\t\t\t\t\tstatus = 204;\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} catch( firefoxAccessException ) {\n\t\t\t\t\t\t\tif ( !isAbort ) {\n\t\t\t\t\t\t\t\tcomplete( -1, firefoxAccessException );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Call complete if needed\n\t\t\t\t\t\tif ( responses ) {\n\t\t\t\t\t\t\tcomplete( status, statusText, responses, responseHeaders );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tif ( !s.async ) {\n\t\t\t\t\t\t// if we're in sync mode we fire the callback\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t} else if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t// (IE6 & IE7) if it's in cache and has been\n\t\t\t\t\t\t// retrieved directly we need to fire the callback\n\t\t\t\t\t\tsetTimeout( callback );\n\t\t\t\t\t} else {\n\t\t\t\t\t\thandle = ++xhrId;\n\t\t\t\t\t\tif ( xhrOnUnloadAbort ) {\n\t\t\t\t\t\t\t// Create the active xhrs callbacks list if needed\n\t\t\t\t\t\t\t// and attach the unload handler\n\t\t\t\t\t\t\tif ( !xhrCallbacks ) {\n\t\t\t\t\t\t\t\txhrCallbacks = {};\n\t\t\t\t\t\t\t\tjQuery( window ).unload( xhrOnUnloadAbort );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Add to list of active xhrs callbacks\n\t\t\t\t\t\t\txhrCallbacks[ handle ] = callback;\n\t\t\t\t\t\t}\n\t\t\t\t\t\txhr.onreadystatechange = callback;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tabort: function() {\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tcallback( undefined, true );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t});\n}\nvar fxNow, timerId,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trfxnum = new RegExp( \"^(?:([+-])=|)(\" + core_pnum + \")([a-z%]*)$\", \"i\" ),\n\trrun = /queueHooks$/,\n\tanimationPrefilters = [ defaultPrefilter ],\n\ttweeners = {\n\t\t\"*\": [function( prop, value ) {\n\t\t\tvar end, unit,\n\t\t\t\ttween = this.createTween( prop, value ),\n\t\t\t\tparts = rfxnum.exec( value ),\n\t\t\t\ttarget = tween.cur(),\n\t\t\t\tstart = +target || 0,\n\t\t\t\tscale = 1,\n\t\t\t\tmaxIterations = 20;\n\n\t\t\tif ( parts ) {\n\t\t\t\tend = +parts[2];\n\t\t\t\tunit = parts[3] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\n\t\t\t\t// We need to compute starting value\n\t\t\t\tif ( unit !== \"px\" && start ) {\n\t\t\t\t\t// Iteratively approximate from a nonzero starting point\n\t\t\t\t\t// Prefer the current property, because this process will be trivial if it uses the same units\n\t\t\t\t\t// Fallback to end or a simple constant\n\t\t\t\t\tstart = jQuery.css( tween.elem, prop, true ) || end || 1;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\t// If previous iteration zeroed out, double until we get *something*\n\t\t\t\t\t\t// Use a string for doubling factor so we don't accidentally see scale as unchanged below\n\t\t\t\t\t\tscale = scale || \".5\";\n\n\t\t\t\t\t\t// Adjust and apply\n\t\t\t\t\t\tstart = start / scale;\n\t\t\t\t\t\tjQuery.style( tween.elem, prop, start + unit );\n\n\t\t\t\t\t// Update scale, tolerating zero or NaN from tween.cur()\n\t\t\t\t\t// And breaking the loop if scale is unchanged or perfect, or if we've just had enough\n\t\t\t\t\t} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );\n\t\t\t\t}\n\n\t\t\t\ttween.unit = unit;\n\t\t\t\ttween.start = start;\n\t\t\t\t// If a +=/-= token was provided, we're doing a relative animation\n\t\t\t\ttween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;\n\t\t\t}\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\nfunction createTweens( animation, props ) {\n\tjQuery.each( props, function( prop, value ) {\n\t\tvar collection = ( tweeners[ prop ] || [] ).concat( tweeners[ \"*\" ] ),\n\t\t\tindex = 0,\n\t\t\tlength = collection.length;\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tif ( collection[ index ].call( animation, prop, value ) ) {\n\n\t\t\t\t// we're done with this property\n\t\t\t\treturn;\n\t\t\t}\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// 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\n\t\t\t\t// 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\tcreateTweens( animation, props );\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\nfunction propFilter( props, specialEasing ) {\n\tvar value, name, index, easing, 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 wont overwrite keys already present.\n\t\t\t// also - reusing 'index' from above 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\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\nfunction defaultPrefilter( elem, props, opts ) {\n\t/*jshint validthis:true */\n\tvar prop, index, length,\n\t\tvalue, dataShow, toggle,\n\t\ttween, hooks, oldfire,\n\t\tanim = this,\n\t\tstyle = elem.style,\n\t\torig = {},\n\t\thandled = [],\n\t\thidden = elem.nodeType && isHidden( elem );\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// doing this makes sure that the complete handler will be called\n\t\t\t// 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 IE does 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\tif ( jQuery.css( elem, \"display\" ) === \"inline\" &&\n\t\t\t\tjQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t// inline-level elements accept inline-block;\n\t\t\t// block-level elements need to be inline with layout\n\t\t\tif ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === \"inline\" ) {\n\t\t\t\tstyle.display = \"inline-block\";\n\n\t\t\t} else {\n\t\t\t\tstyle.zoom = 1;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tif ( !jQuery.support.shrinkWrapBlocks ) {\n\t\t\tanim.always(function() {\n\t\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t\t});\n\t\t}\n\t}\n\n\n\t// show/hide pass\n\tfor ( index in props ) {\n\t\tvalue = props[ index ];\n\t\tif ( rfxtypes.exec( value ) ) {\n\t\t\tdelete props[ index ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\thandled.push( index );\n\t\t}\n\t}\n\n\tlength = handled.length;\n\tif ( length ) {\n\t\tdataShow = jQuery._data( elem, \"fxshow\" ) || jQuery._data( elem, \"fxshow\", {} );\n\t\tif ( \"hidden\" in dataShow ) {\n\t\t\thidden = dataShow.hidden;\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\t\t\tjQuery._removeData( 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 ( index = 0 ; index < length ; index++ ) {\n\t\t\tprop = handled[ index ];\n\t\t\ttween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );\n\t\t\torig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );\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\t}\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// so, 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 - use cssHook if its there - use .style if its\n\t\t\t// 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// Remove in 2.0 - this supports IE8's panic based approach\n// to setting things on disconnected nodes\n\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.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\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\t\t\t\tdoAnimation.finish = function() {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t};\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || jQuery._data( 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 = jQuery._data( 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 will dequeue\n\t\t\t// 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 = jQuery._data( 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.cur && hooks.cur.finish ) {\n\t\t\t\thooks.cur.finish.call( this );\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\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\tattrs = { height: type },\n\t\ti = 0;\n\n\t// if we include width, step value is 1 to do all cssExpand values,\n\t// if we don't include width, 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\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.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.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.timers = [];\njQuery.fx = Tween.prototype.init;\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ttimers = jQuery.timers,\n\t\ti = 0;\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\tif ( timer() && jQuery.timers.push( timer ) ) {\n\t\tjQuery.fx.start();\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// Back Compat <1.8 extension point\njQuery.fx.step = {};\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.animated = function( elem ) {\n\t\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\t\treturn elem === fn.elem;\n\t\t}).length;\n\t};\n}\njQuery.fn.offset = function( options ) {\n\tif ( arguments.length ) {\n\t\treturn options === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function( i ) {\n\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t});\n\t}\n\n\tvar docElem, win,\n\t\tbox = { top: 0, left: 0 },\n\t\telem = this[ 0 ],\n\t\tdoc = elem && elem.ownerDocument;\n\n\tif ( !doc ) {\n\t\treturn;\n\t}\n\n\tdocElem = doc.documentElement;\n\n\t// Make sure it's not a disconnected DOM node\n\tif ( !jQuery.contains( docElem, elem ) ) {\n\t\treturn box;\n\t}\n\n\t// If we don't have gBCR, just use 0,0 rather than error\n\t// BlackBerry 5, iOS 3 (original iPhone)\n\tif ( typeof elem.getBoundingClientRect !== core_strundefined ) {\n\t\tbox = elem.getBoundingClientRect();\n\t}\n\twin = getWindow( doc );\n\treturn {\n\t\ttop: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),\n\t\tleft: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )\n\t};\n};\n\njQuery.offset = {\n\n\tsetOffset: function( elem, options, i ) {\n\t\tvar position = jQuery.css( elem, \"position\" );\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\tvar curElem = jQuery( elem ),\n\t\t\tcurOffset = curElem.offset(),\n\t\t\tcurCSSTop = jQuery.css( elem, \"top\" ),\n\t\t\tcurCSSLeft = jQuery.css( elem, \"left\" ),\n\t\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) && jQuery.inArray(\"auto\", [curCSSTop, curCSSLeft]) > -1,\n\t\t\tprops = {}, curPosition = {}, curTop, curLeft;\n\n\t\t// need to be able to calculate position if either 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\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\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\n\njQuery.fn.extend({\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\tparentOffset = { top: 0, left: 0 },\n\t\t\telem = this[ 0 ];\n\n\t\t// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\t\t\t// we assume that getBoundingClientRect is available when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\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\t// note: when an element has margin: auto the offsetLeft and marginLeft\n\t\t// are the same in Safari causing offset.left to incorrectly be 0\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 || document.documentElement;\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\t\t\treturn offsetParent || document.documentElement;\n\t\t});\n\t}\n});\n\n\n// Create scrollLeft and scrollTop methods\njQuery.each( {scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\"}, function( method, prop ) {\n\tvar top = /Y/.test( prop );\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn jQuery.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 ? (prop in win) ? win[ prop ] :\n\t\t\t\t\twin.document.documentElement[ method ] :\n\t\t\t\t\telem[ 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 : jQuery( win ).scrollLeft(),\n\t\t\t\t\ttop ? val : jQuery( win ).scrollTop()\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\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ?\n\t\telem :\n\t\telem.nodeType === 9 ?\n\t\t\telem.defaultView || elem.parentWindow :\n\t\t\tfalse;\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 jQuery.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], whichever is greatest\n\t\t\t\t\t// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.\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// Limit scope pollution from any deprecated API\n// (function() {\n\n// })();\n// Expose jQuery to the global object\nwindow.jQuery = window.$ = jQuery;\n\n// Expose jQuery as an AMD module, but only for AMD loaders that\n// understand the issues with loading multiple versions of jQuery\n// in a page that all might call define(). The loader will indicate\n// they have special allowances for multiple jQuery versions by\n// specifying define.amd.jQuery = true. Register as a named module,\n// since jQuery can be concatenated with other files that may use define,\n// but not use a proper concatenation script that understands anonymous\n// AMD modules. A named AMD is safest and most robust way to register.\n// Lowercase jquery is used because AMD module names are derived from\n// file names, and jQuery is normally delivered in a lowercase file name.\n// Do this after creating the global so that if an AMD module wants to call\n// noConflict to hide this version of jQuery, it will work.\nif ( typeof define === \"function\" && define.amd && define.amd.jQuery ) {\n\tdefine( \"jquery\", [], function () { return jQuery; } );\n}\n\n})( window );\n"
  },
  {
    "path": "public/static/lib/layer/2.4/layer.js",
    "content": "/*! layer-v2.4 弹层组件 License LGPL  http://layer.layui.com/ By 贤心 */\n;!function(a,b){\"use strict\";var c,d,e={getPath:function(){var a=document.scripts,b=a[a.length-1],c=b.src;if(!b.getAttribute(\"merge\"))return c.substring(0,c.lastIndexOf(\"/\")+1)}(),enter:function(a){13===a.keyCode&&a.preventDefault()},config:{},end:{},btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],type:[\"dialog\",\"page\",\"iframe\",\"loading\",\"tips\"]},f={v:\"2.4\",ie6:!!a.ActiveXObject&&!a.XMLHttpRequest,index:0,path:e.getPath,config:function(a,b){var d=0;return a=a||{},f.cache=e.config=c.extend(e.config,a),f.path=e.config.path||f.path,\"string\"==typeof a.extend&&(a.extend=[a.extend]),f.use(\"skin/layer.css\",a.extend&&a.extend.length>0?function g(){var c=a.extend;f.use(c[c[d]?d:d-1],d<c.length?function(){return++d,g}():b)}():b),this},use:function(a,b,d){var e=c(\"head\")[0],a=a.replace(/\\s/g,\"\"),g=/\\.css$/.test(a),h=document.createElement(g?\"link\":\"script\"),i=\"layui_layer_\"+a.replace(/\\.|\\//g,\"\");return f.path?(g&&(h.rel=\"stylesheet\"),h[g?\"href\":\"src\"]=/^http:\\/\\//.test(a)?a:f.path+a,h.id=i,c(\"#\"+i)[0]||e.appendChild(h),function j(){(g?1989===parseInt(c(\"#\"+i).css(\"width\")):f[d||i])?function(){b&&b();try{g||e.removeChild(h)}catch(a){}}():setTimeout(j,100)}(),this):void 0},ready:function(a,b){var d=\"function\"==typeof a;return d&&(b=a),f.config(c.extend(e.config,function(){return d?{}:{path:a}}()),b),this},alert:function(a,b,d){var e=\"function\"==typeof b;return e&&(d=b),f.open(c.extend({content:a,yes:d},e?{}:b))},confirm:function(a,b,d,g){var h=\"function\"==typeof b;return h&&(g=d,d=b),f.open(c.extend({content:a,btn:e.btn,yes:d,btn2:g},h?{}:b))},msg:function(a,d,g){var i=\"function\"==typeof d,j=e.config.skin,k=(j?j+\" \"+j+\"-msg\":\"\")||\"layui-layer-msg\",l=h.anim.length-1;return i&&(g=d),f.open(c.extend({content:a,time:3e3,shade:!1,skin:k,title:!1,closeBtn:!1,btn:!1,end:g},i&&!e.config.skin?{skin:k+\" layui-layer-hui\",shift:l}:function(){return d=d||{},(-1===d.icon||d.icon===b&&!e.config.skin)&&(d.skin=k+\" \"+(d.skin||\"layui-layer-hui\")),d}()))},load:function(a,b){return f.open(c.extend({type:3,icon:a||0,shade:.01},b))},tips:function(a,b,d){return f.open(c.extend({type:4,content:[a,b],closeBtn:!1,time:3e3,shade:!1,fix:!1,maxWidth:210},d))}},g=function(a){var b=this;b.index=++f.index,b.config=c.extend({},b.config,e.config,a),b.creat()};g.pt=g.prototype;var h=[\"layui-layer\",\".layui-layer-title\",\".layui-layer-main\",\".layui-layer-dialog\",\"layui-layer-iframe\",\"layui-layer-content\",\"layui-layer-btn\",\"layui-layer-close\"];h.anim=[\"layer-anim\",\"layer-anim-01\",\"layer-anim-02\",\"layer-anim-03\",\"layer-anim-04\",\"layer-anim-05\",\"layer-anim-06\"],g.pt.config={type:0,shade:.3,fix:!0,move:h[1],title:\"&#x4FE1;&#x606F;\",offset:\"auto\",area:\"auto\",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,shift:0,icon:-1,scrollbar:!0,tips:2},g.pt.vessel=function(a,b){var c=this,d=c.index,f=c.config,g=f.zIndex+d,i=\"object\"==typeof f.title,j=f.maxmin&&(1===f.type||2===f.type),k=f.title?'<div class=\"layui-layer-title\" style=\"'+(i?f.title[1]:\"\")+'\">'+(i?f.title[0]:f.title)+\"</div>\":\"\";return f.zIndex=g,b([f.shade?'<div class=\"layui-layer-shade\" id=\"layui-layer-shade'+d+'\" times=\"'+d+'\" style=\"'+(\"z-index:\"+(g-1)+\"; background-color:\"+(f.shade[1]||\"#000\")+\"; opacity:\"+(f.shade[0]||f.shade)+\"; filter:alpha(opacity=\"+(100*f.shade[0]||100*f.shade)+\");\")+'\"></div>':\"\",'<div class=\"'+h[0]+(\" layui-layer-\"+e.type[f.type])+(0!=f.type&&2!=f.type||f.shade?\"\":\" layui-layer-border\")+\" \"+(f.skin||\"\")+'\" id=\"'+h[0]+d+'\" type=\"'+e.type[f.type]+'\" times=\"'+d+'\" showtime=\"'+f.time+'\" conType=\"'+(a?\"object\":\"string\")+'\" style=\"z-index: '+g+\"; width:\"+f.area[0]+\";height:\"+f.area[1]+(f.fix?\"\":\";position:absolute;\")+'\">'+(a&&2!=f.type?\"\":k)+'<div id=\"'+(f.id||\"\")+'\" class=\"layui-layer-content'+(0==f.type&&-1!==f.icon?\" layui-layer-padding\":\"\")+(3==f.type?\" layui-layer-loading\"+f.icon:\"\")+'\">'+(0==f.type&&-1!==f.icon?'<i class=\"layui-layer-ico layui-layer-ico'+f.icon+'\"></i>':\"\")+(1==f.type&&a?\"\":f.content||\"\")+'</div><span class=\"layui-layer-setwin\">'+function(){var a=j?'<a class=\"layui-layer-min\" href=\"javascript:;\"><cite></cite></a><a class=\"layui-layer-ico layui-layer-max\" href=\"javascript:;\"></a>':\"\";return f.closeBtn&&(a+='<a class=\"layui-layer-ico '+h[7]+\" \"+h[7]+(f.title?f.closeBtn:4==f.type?\"1\":\"2\")+'\" href=\"javascript:;\"></a>'),a}()+\"</span>\"+(f.btn?function(){var a=\"\";\"string\"==typeof f.btn&&(f.btn=[f.btn]);for(var b=0,c=f.btn.length;c>b;b++)a+='<a class=\"'+h[6]+b+'\">'+f.btn[b]+\"</a>\";return'<div class=\"'+h[6]+'\">'+a+\"</div>\"}():\"\")+\"</div>\"],k),c},g.pt.creat=function(){var a=this,b=a.config,g=a.index,i=b.content,j=\"object\"==typeof i;if(!c(\"#\"+b.id)[0]){switch(\"string\"==typeof b.area&&(b.area=\"auto\"===b.area?[\"\",\"\"]:[b.area,\"\"]),b.type){case 0:b.btn=\"btn\"in b?b.btn:e.btn[0],f.closeAll(\"dialog\");break;case 2:var i=b.content=j?b.content:[b.content||\"http://layer.layui.com\",\"auto\"];b.content='<iframe scrolling=\"'+(b.content[1]||\"auto\")+'\" allowtransparency=\"true\" id=\"'+h[4]+g+'\" name=\"'+h[4]+g+'\" onload=\"this.className=\\'\\';\" class=\"layui-layer-load\" frameborder=\"0\" src=\"'+b.content[0]+'\"></iframe>';break;case 3:b.title=!1,b.closeBtn=!1,-1===b.icon&&0===b.icon,f.closeAll(\"loading\");break;case 4:j||(b.content=[b.content,\"body\"]),b.follow=b.content[1],b.content=b.content[0]+'<i class=\"layui-layer-TipsG\"></i>',b.title=!1,b.tips=\"object\"==typeof b.tips?b.tips:[b.tips,!0],b.tipsMore||f.closeAll(\"tips\")}a.vessel(j,function(d,e){c(\"body\").append(d[0]),j?function(){2==b.type||4==b.type?function(){c(\"body\").append(d[1])}():function(){i.parents(\".\"+h[0])[0]||(i.show().addClass(\"layui-layer-wrap\").wrap(d[1]),c(\"#\"+h[0]+g).find(\".\"+h[5]).before(e))}()}():c(\"body\").append(d[1]),a.layero=c(\"#\"+h[0]+g),b.scrollbar||h.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",g)}).auto(g),2==b.type&&f.ie6&&a.layero.find(\"iframe\").attr(\"src\",i[0]),c(document).off(\"keydown\",e.enter).on(\"keydown\",e.enter),a.layero.on(\"keydown\",function(a){c(document).off(\"keydown\",e.enter)}),4==b.type?a.tips():a.offset(),b.fix&&d.on(\"resize\",function(){a.offset(),(/^\\d+%$/.test(b.area[0])||/^\\d+%$/.test(b.area[1]))&&a.auto(g),4==b.type&&a.tips()}),b.time<=0||setTimeout(function(){f.close(a.index)},b.time),a.move().callback(),h.anim[b.shift]&&a.layero.addClass(h.anim[b.shift])}},g.pt.auto=function(a){function b(a){a=g.find(a),a.height(i[1]-j-k-2*(0|parseFloat(a.css(\"padding\"))))}var e=this,f=e.config,g=c(\"#\"+h[0]+a);\"\"===f.area[0]&&f.maxWidth>0&&(/MSIE 7/.test(navigator.userAgent)&&f.btn&&g.width(g.innerWidth()),g.outerWidth()>f.maxWidth&&g.width(f.maxWidth));var i=[g.innerWidth(),g.innerHeight()],j=g.find(h[1]).outerHeight()||0,k=g.find(\".\"+h[6]).outerHeight()||0;switch(f.type){case 2:b(\"iframe\");break;default:\"\"===f.area[1]?f.fix&&i[1]>=d.height()&&(i[1]=d.height(),b(\".\"+h[5])):b(\".\"+h[5])}return e},g.pt.offset=function(){var a=this,b=a.config,c=a.layero,e=[c.outerWidth(),c.outerHeight()],f=\"object\"==typeof b.offset;a.offsetTop=(d.height()-e[1])/2,a.offsetLeft=(d.width()-e[0])/2,f?(a.offsetTop=b.offset[0],a.offsetLeft=b.offset[1]||a.offsetLeft):\"auto\"!==b.offset&&(a.offsetTop=b.offset,\"rb\"===b.offset&&(a.offsetTop=d.height()-e[1],a.offsetLeft=d.width()-e[0])),b.fix||(a.offsetTop=/%$/.test(a.offsetTop)?d.height()*parseFloat(a.offsetTop)/100:parseFloat(a.offsetTop),a.offsetLeft=/%$/.test(a.offsetLeft)?d.width()*parseFloat(a.offsetLeft)/100:parseFloat(a.offsetLeft),a.offsetTop+=d.scrollTop(),a.offsetLeft+=d.scrollLeft()),c.css({top:a.offsetTop,left:a.offsetLeft})},g.pt.tips=function(){var a=this,b=a.config,e=a.layero,f=[e.outerWidth(),e.outerHeight()],g=c(b.follow);g[0]||(g=c(\"body\"));var i={width:g.outerWidth(),height:g.outerHeight(),top:g.offset().top,left:g.offset().left},j=e.find(\".layui-layer-TipsG\"),k=b.tips[0];b.tips[1]||j.remove(),i.autoLeft=function(){i.left+f[0]-d.width()>0?(i.tipLeft=i.left+i.width-f[0],j.css({right:12,left:\"auto\"})):i.tipLeft=i.left},i.where=[function(){i.autoLeft(),i.tipTop=i.top-f[1]-10,j.removeClass(\"layui-layer-TipsB\").addClass(\"layui-layer-TipsT\").css(\"border-right-color\",b.tips[1])},function(){i.tipLeft=i.left+i.width+10,i.tipTop=i.top,j.removeClass(\"layui-layer-TipsL\").addClass(\"layui-layer-TipsR\").css(\"border-bottom-color\",b.tips[1])},function(){i.autoLeft(),i.tipTop=i.top+i.height+10,j.removeClass(\"layui-layer-TipsT\").addClass(\"layui-layer-TipsB\").css(\"border-right-color\",b.tips[1])},function(){i.tipLeft=i.left-f[0]-10,i.tipTop=i.top,j.removeClass(\"layui-layer-TipsR\").addClass(\"layui-layer-TipsL\").css(\"border-bottom-color\",b.tips[1])}],i.where[k-1](),1===k?i.top-(d.scrollTop()+f[1]+16)<0&&i.where[2]():2===k?d.width()-(i.left+i.width+f[0]+16)>0||i.where[3]():3===k?i.top-d.scrollTop()+i.height+f[1]+16-d.height()>0&&i.where[0]():4===k&&f[0]+16-i.left>0&&i.where[1](),e.find(\".\"+h[5]).css({\"background-color\":b.tips[1],\"padding-right\":b.closeBtn?\"30px\":\"\"}),e.css({left:i.tipLeft-(b.fix?d.scrollLeft():0),top:i.tipTop-(b.fix?d.scrollTop():0)})},g.pt.move=function(){var a=this,b=a.config,e={setY:0,moveLayer:function(){var a=e.layero,b=parseInt(a.css(\"margin-left\")),c=parseInt(e.move.css(\"left\"));0===b||(c-=b),\"fixed\"!==a.css(\"position\")&&(c-=a.parent().offset().left,e.setY=0),a.css({left:c,top:parseInt(e.move.css(\"top\"))-e.setY})}},f=a.layero.find(b.move);return b.move&&f.attr(\"move\",\"ok\"),f.css({cursor:b.move?\"move\":\"auto\"}),c(b.move).on(\"mousedown\",function(a){if(a.preventDefault(),\"ok\"===c(this).attr(\"move\")){e.ismove=!0,e.layero=c(this).parents(\".\"+h[0]);var f=e.layero.offset().left,g=e.layero.offset().top,i=e.layero.outerWidth()-6,j=e.layero.outerHeight()-6;c(\"#layui-layer-moves\")[0]||c(\"body\").append('<div id=\"layui-layer-moves\" class=\"layui-layer-moves\" style=\"left:'+f+\"px; top:\"+g+\"px; width:\"+i+\"px; height:\"+j+'px; z-index:2147483584\"></div>'),e.move=c(\"#layui-layer-moves\"),b.moveType&&e.move.css({visibility:\"hidden\"}),e.moveX=a.pageX-e.move.position().left,e.moveY=a.pageY-e.move.position().top,\"fixed\"!==e.layero.css(\"position\")||(e.setY=d.scrollTop())}}),c(document).mousemove(function(a){if(e.ismove){var c=a.pageX-e.moveX,f=a.pageY-e.moveY;if(a.preventDefault(),!b.moveOut){e.setY=d.scrollTop();var g=d.width()-e.move.outerWidth(),h=e.setY;0>c&&(c=0),c>g&&(c=g),h>f&&(f=h),f>d.height()-e.move.outerHeight()+e.setY&&(f=d.height()-e.move.outerHeight()+e.setY)}e.move.css({left:c,top:f}),b.moveType&&e.moveLayer(),c=f=g=h=null}}).mouseup(function(){try{e.ismove&&(e.moveLayer(),e.move.remove(),b.moveEnd&&b.moveEnd()),e.ismove=!1}catch(a){e.ismove=!1}}),a},g.pt.callback=function(){function a(){var a=g.cancel&&g.cancel(b.index,d);a===!1||f.close(b.index)}var b=this,d=b.layero,g=b.config;b.openLayer(),g.success&&(2==g.type?d.find(\"iframe\").on(\"load\",function(){g.success(d,b.index)}):g.success(d,b.index)),f.ie6&&b.IE6(d),d.find(\".\"+h[6]).children(\"a\").on(\"click\",function(){var a=c(this).index();if(0===a)g.yes?g.yes(b.index,d):g.btn1?g.btn1(b.index,d):f.close(b.index);else{var e=g[\"btn\"+(a+1)]&&g[\"btn\"+(a+1)](b.index,d);e===!1||f.close(b.index)}}),d.find(\".\"+h[7]).on(\"click\",a),g.shadeClose&&c(\"#layui-layer-shade\"+b.index).on(\"click\",function(){f.close(b.index)}),d.find(\".layui-layer-min\").on(\"click\",function(){var a=g.min&&g.min(d);a===!1||f.min(b.index,g)}),d.find(\".layui-layer-max\").on(\"click\",function(){c(this).hasClass(\"layui-layer-maxmin\")?(f.restore(b.index),g.restore&&g.restore(d)):(f.full(b.index,g),setTimeout(function(){g.full&&g.full(d)},100))}),g.end&&(e.end[b.index]=g.end)},e.reselect=function(){c.each(c(\"select\"),function(a,b){var d=c(this);d.parents(\".\"+h[0])[0]||1==d.attr(\"layer\")&&c(\".\"+h[0]).length<1&&d.removeAttr(\"layer\").show(),d=null})},g.pt.IE6=function(a){function b(){a.css({top:f+(e.config.fix?d.scrollTop():0)})}var e=this,f=a.offset().top;b(),d.scroll(b),c(\"select\").each(function(a,b){var d=c(this);d.parents(\".\"+h[0])[0]||\"none\"===d.css(\"display\")||d.attr({layer:\"1\"}).hide(),d=null})},g.pt.openLayer=function(){var a=this;f.zIndex=a.config.zIndex,f.setTop=function(a){var b=function(){f.zIndex++,a.css(\"z-index\",f.zIndex+1)};return f.zIndex=parseInt(a[0].style.zIndex),a.on(\"mousedown\",b),f.zIndex}},e.record=function(a){var b=[a.width(),a.height(),a.position().top,a.position().left+parseFloat(a.css(\"margin-left\"))];a.find(\".layui-layer-max\").addClass(\"layui-layer-maxmin\"),a.attr({area:b})},e.rescollbar=function(a){h.html.attr(\"layer-full\")==a&&(h.html[0].style.removeProperty?h.html[0].style.removeProperty(\"overflow\"):h.html[0].style.removeAttribute(\"overflow\"),h.html.removeAttr(\"layer-full\"))},a.layer=f,f.getChildFrame=function(a,b){return b=b||c(\".\"+h[4]).attr(\"times\"),c(\"#\"+h[0]+b).find(\"iframe\").contents().find(a)},f.getFrameIndex=function(a){return c(\"#\"+a).parents(\".\"+h[4]).attr(\"times\")},f.iframeAuto=function(a){if(a){var b=f.getChildFrame(\"html\",a).outerHeight(),d=c(\"#\"+h[0]+a),e=d.find(h[1]).outerHeight()||0,g=d.find(\".\"+h[6]).outerHeight()||0;d.css({height:b+e+g}),d.find(\"iframe\").css({height:b})}},f.iframeSrc=function(a,b){c(\"#\"+h[0]+a).find(\"iframe\").attr(\"src\",b)},f.style=function(a,b){var d=c(\"#\"+h[0]+a),f=d.attr(\"type\"),g=d.find(h[1]).outerHeight()||0,i=d.find(\".\"+h[6]).outerHeight()||0;(f===e.type[1]||f===e.type[2])&&(d.css(b),f===e.type[2]&&d.find(\"iframe\").css({height:parseFloat(b.height)-g-i}))},f.min=function(a,b){var d=c(\"#\"+h[0]+a),g=d.find(h[1]).outerHeight()||0;e.record(d),f.style(a,{width:180,height:g,overflow:\"hidden\"}),d.find(\".layui-layer-min\").hide(),\"page\"===d.attr(\"type\")&&d.find(h[4]).hide(),e.rescollbar(a)},f.restore=function(a){var b=c(\"#\"+h[0]+a),d=b.attr(\"area\").split(\",\");b.attr(\"type\");f.style(a,{width:parseFloat(d[0]),height:parseFloat(d[1]),top:parseFloat(d[2]),left:parseFloat(d[3]),overflow:\"visible\"}),b.find(\".layui-layer-max\").removeClass(\"layui-layer-maxmin\"),b.find(\".layui-layer-min\").show(),\"page\"===b.attr(\"type\")&&b.find(h[4]).show(),e.rescollbar(a)},f.full=function(a){var b,g=c(\"#\"+h[0]+a);e.record(g),h.html.attr(\"layer-full\")||h.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",a),clearTimeout(b),b=setTimeout(function(){var b=\"fixed\"===g.css(\"position\");f.style(a,{top:b?0:d.scrollTop(),left:b?0:d.scrollLeft(),width:d.width(),height:d.height()}),g.find(\".layui-layer-min\").hide()},100)},f.title=function(a,b){var d=c(\"#\"+h[0]+(b||f.index)).find(h[1]);d.html(a)},f.close=function(a){var b=c(\"#\"+h[0]+a),d=b.attr(\"type\");if(b[0]){if(d===e.type[1]&&\"object\"===b.attr(\"conType\")){b.children(\":not(.\"+h[5]+\")\").remove();for(var g=0;2>g;g++)b.find(\".layui-layer-wrap\").unwrap().hide()}else{if(d===e.type[2])try{var i=c(\"#\"+h[4]+a)[0];i.contentWindow.document.write(\"\"),i.contentWindow.close(),b.find(\".\"+h[5])[0].removeChild(i)}catch(j){}b[0].innerHTML=\"\",b.remove()}c(\"#layui-layer-moves, #layui-layer-shade\"+a).remove(),f.ie6&&e.reselect(),e.rescollbar(a),c(document).off(\"keydown\",e.enter),\"function\"==typeof e.end[a]&&e.end[a](),delete e.end[a]}},f.closeAll=function(a){c.each(c(\".\"+h[0]),function(){var b=c(this),d=a?b.attr(\"type\")===a:1;d&&f.close(b.attr(\"times\")),d=null})};var i=f.cache||{},j=function(a){return i.skin?\" \"+i.skin+\" \"+i.skin+\"-\"+a:\"\"};f.prompt=function(a,b){a=a||{},\"function\"==typeof a&&(b=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 f.open(c.extend({btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],content:e,skin:\"layui-layer-prompt\"+j(\"prompt\"),success:function(a){d=a.find(\".layui-layer-input\"),d.focus()},yes:function(c){var e=d.val();\"\"===e?d.focus():e.length>(a.maxlength||500)?f.tips(\"&#x6700;&#x591A;&#x8F93;&#x5165;\"+(a.maxlength||500)+\"&#x4E2A;&#x5B57;&#x6570;\",d,{tips:1}):b&&b(e,c,d)}},a))},f.tab=function(a){a=a||{};var b=a.tab||{};return f.open(c.extend({type:1,skin:\"layui-layer-tab\"+j(\"tab\"),title:function(){var a=b.length,c=1,d=\"\";if(a>0)for(d='<span class=\"layui-layer-tabnow\">'+b[0].title+\"</span>\";a>c;c++)d+=\"<span>\"+b[c].title+\"</span>\";return d}(),content:'<ul class=\"layui-layer-tabmain\">'+function(){var a=b.length,c=1,d=\"\";if(a>0)for(d='<li class=\"layui-layer-tabli xubox_tab_layer\">'+(b[0].content||\"no content\")+\"</li>\";a>c;c++)d+='<li class=\"layui-layer-tabli\">'+(b[c].content||\"no  content\")+\"</li>\";return d}()+\"</ul>\",success:function(b){var d=b.find(\".layui-layer-title\").children(),e=b.find(\".layui-layer-tabmain\").children();d.on(\"mousedown\",function(b){b.stopPropagation?b.stopPropagation():b.cancelBubble=!0;var d=c(this),f=d.index();d.addClass(\"layui-layer-tabnow\").siblings().removeClass(\"layui-layer-tabnow\"),e.eq(f).show().siblings().hide(),\"function\"==typeof a.change&&a.change(f)})}},a))},f.photos=function(b,d,e){function g(a,b,c){var d=new Image;return d.src=a,d.complete?b(d):(d.onload=function(){d.onload=null,b(d)},void(d.onerror=function(a){d.onerror=null,c(a)}))}var h={};if(b=b||{},b.photos){var i=b.photos.constructor===Object,k=i?b.photos:{},l=k.data||[],m=k.start||0;if(h.imgIndex=(0|m)+1,b.img=b.img||\"img\",i){if(0===l.length)return f.msg(\"&#x6CA1;&#x6709;&#x56FE;&#x7247;\")}else{var n=c(b.photos),o=function(){l=[],n.find(b.img).each(function(a){var b=c(this);b.attr(\"layer-index\",a),l.push({alt:b.attr(\"alt\"),pid:b.attr(\"layer-pid\"),src:b.attr(\"layer-src\")||b.attr(\"src\"),thumb:b.attr(\"src\")})})};if(o(),0===l.length)return;if(d||n.on(\"click\",b.img,function(){var a=c(this),d=a.attr(\"layer-index\");f.photos(c.extend(b,{photos:{start:d,data:l,tab:b.tab},full:b.full}),!0),o()}),!d)return}h.imgprev=function(a){h.imgIndex--,h.imgIndex<1&&(h.imgIndex=l.length),h.tabimg(a)},h.imgnext=function(a,b){h.imgIndex++,h.imgIndex>l.length&&(h.imgIndex=1,b)||h.tabimg(a)},h.keyup=function(a){if(!h.end){var b=a.keyCode;a.preventDefault(),37===b?h.imgprev(!0):39===b?h.imgnext(!0):27===b&&f.close(h.index)}},h.tabimg=function(a){l.length<=1||(k.start=h.imgIndex-1,f.close(h.index),f.photos(b,!0,a))},h.event=function(){h.bigimg.hover(function(){h.imgsee.show()},function(){h.imgsee.hide()}),h.bigimg.find(\".layui-layer-imgprev\").on(\"click\",function(a){a.preventDefault(),h.imgprev()}),h.bigimg.find(\".layui-layer-imgnext\").on(\"click\",function(a){a.preventDefault(),h.imgnext()}),c(document).on(\"keyup\",h.keyup)},h.loadi=f.load(1,{shade:\"shade\"in b?!1:.9,scrollbar:!1}),g(l[m].src,function(d){f.close(h.loadi),h.index=f.open(c.extend({type:1,area:function(){var e=[d.width,d.height],f=[c(a).width()-50,c(a).height()-50];return!b.full&&e[0]>f[0]&&(e[0]=f[0],e[1]=e[0]*d.height/d.width),[e[0]+\"px\",e[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\"+j(\"photos\"),content:'<div class=\"layui-layer-phimg\"><img src=\"'+l[m].src+'\" alt=\"'+(l[m].alt||\"\")+'\" layer-pid=\"'+l[m].pid+'\"><div class=\"layui-layer-imgsee\">'+(l.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:'+(e?\"block\":\"\")+'\"><span class=\"layui-layer-imgtit\"><a href=\"javascript:;\">'+(l[m].alt||\"\")+\"</a><em>\"+h.imgIndex+\"/\"+l.length+\"</em></span></div></div></div>\",success:function(a,c){h.bigimg=a.find(\".layui-layer-phimg\"),h.imgsee=a.find(\".layui-layer-imguide,.layui-layer-imgbar\"),h.event(a),b.tab&&b.tab(l[m],a)},end:function(){h.end=!0,c(document).off(\"keyup\",h.keyup)}},b))},function(){f.close(h.loadi),f.msg(\"&#x5F53;&#x524D;&#x56FE;&#x7247;&#x5730;&#x5740;&#x5F02;&#x5E38;<br>&#x662F;&#x5426;&#x7EE7;&#x7EED;&#x67E5;&#x770B;&#x4E0B;&#x4E00;&#x5F20;&#xFF1F;\",{time:3e4,btn:[\"&#x4E0B;&#x4E00;&#x5F20;\",\"&#x4E0D;&#x770B;&#x4E86;\"],yes:function(){l.length>1&&h.imgnext(!0,!0)}})})}},e.run=function(){c=jQuery,d=c(a),h.html=c(\"html\"),f.open=function(a){var b=new g(a);return b.index}},\"function\"==typeof define?define(function(){return e.run(),f}):function(){e.run(),f.use(\"skin/layer.css\")}()}(window);"
  },
  {
    "path": "public/static/lib/layer/2.4/skin/layer.css",
    "content": "/*!\n \n @Name: layer's style\n @Author: 贤心\n @Blog： sentsin.com\n \n */.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}*html{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{-webkit-overflow-scrolling:touch;top:150px;left:0;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)}}.layer-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)}}.layer-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}}.layer-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)}}.layer-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}}.layer-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)}}.layer-anim-04{-webkit-animation-name:rollIn;animation-name:rollIn}@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layer-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)}}.layer-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;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: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:-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 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;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 .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-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}.layui-layer-iconext{background:url(default/icon-ext.png) no-repeat}.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}.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}"
  },
  {
    "path": "runtime/.gitignore",
    "content": "*\n!.gitignore"
  },
  {
    "path": "tests/ExampleTest.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\nnamespace tests;\n\nclass ExampleTest extends TestCase\n{\n\n    public function testBasicExample()\n    {\n        $this->visit('/')->see('ThinkPHP');\n    }\n}"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\nnamespace tests;\n\nclass TestCase extends \\think\\testing\\TestCase\n{\n    protected $baseUrl = 'http://localhost';\n}"
  },
  {
    "path": "think",
    "content": "#!/usr/bin/env php\n<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\n// 定义项目路径\ndefine('APP_PATH', __DIR__ . '/application/');\n\n// 加载框架引导文件\nrequire __DIR__.'/thinkphp/console.php';\n"
  },
  {
    "path": "thinkphp/.gitignore",
    "content": "/composer.lock\n/vendor\n.idea\n.DS_Store\n"
  },
  {
    "path": "thinkphp/.htaccess",
    "content": "deny from all"
  },
  {
    "path": "thinkphp/.travis.yml",
    "content": "sudo: false\n\nlanguage: php\n\nservices:\n  - memcached\n  - mongodb\n  - mysql\n  - postgresql\n  - redis-server\n\nmatrix:\n  fast_finish: true\n  include:\n    - php: 5.4\n    - php: 5.5\n    - php: 5.6\n    - php: 7.0\n    - php: hhvm\n  allow_failures:\n    - php: hhvm\n\ncache:\n  directories:\n    - $HOME/.composer/cache\n\nbefore_install:\n  - composer self-update\n  - mysql -e \"create database IF NOT EXISTS test;\" -uroot\n  - psql -c 'DROP DATABASE IF EXISTS test;' -U postgres\n  - psql -c 'create database test;' -U postgres\n\ninstall:\n  - ./tests/script/install.sh\n\nscript:\n  ## LINT\n  - find . -path ./vendor -prune -o -type f -name \\*.php -exec php -l {} \\;\n  ## PHP Copy/Paste Detector\n  - vendor/bin/phpcpd --verbose --exclude vendor ./ || true\n  ## PHPLOC\n  - vendor/bin/phploc --exclude vendor ./\n  ## PHPUNIT\n  - vendor/bin/phpunit --coverage-clover=coverage.xml --configuration=phpunit.xml\n\nafter_success:\n  - bash <(curl -s https://codecov.io/bash)\n"
  },
  {
    "path": "thinkphp/CONTRIBUTING.md",
    "content": "如何贡献我的源代码\n===\n\n此文档介绍了 ThinkPHP 团队的组成以及运转机制，您提交的代码将给 ThinkPHP 项目带来什么好处，以及如何才能加入我们的行列。\n\n## 通过 Github 贡献代码\n\nThinkPHP 目前使用 Git 来控制程序版本，如果你想为 ThinkPHP 贡献源代码，请先大致了解 Git 的使用方法。我们目前把项目托管在 GitHub 上，任何 GitHub 用户都可以向我们贡献代码。\n\n参与的方式很简单，`fork`一份 ThinkPHP 的代码到你的仓库中，修改后提交，并向我们发起`pull request`申请，我们会及时对代码进行审查并处理你的申请并。审查通过后，你的代码将被`merge`进我们的仓库中，这样你就会自动出现在贡献者名单里了，非常方便。\n\n我们希望你贡献的代码符合：\n\n* ThinkPHP 的编码规范\n* 适当的注释，能让其他人读懂\n* 遵循 Apache2 开源协议\n\n**如果想要了解更多细节或有任何疑问，请继续阅读下面的内容**\n\n### 注意事项\n\n* 本项目代码格式化标准选用 [**PSR-2**](http://www.kancloud.cn/thinkphp/php-fig-psr/3141)；\n* 类名和类文件名遵循 [**PSR-4**](http://www.kancloud.cn/thinkphp/php-fig-psr/3144)；\n* 对于 Issues 的处理，请使用诸如 `fix #xxx(Issue ID)` 的 commit title 直接关闭 issue。\n* 系统会自动在 PHP 5.4 5.5 5.6 7.0 和 HHVM 上测试修改，其中 HHVM 下的测试容许报错，请确保你的修改符合 PHP 5.4 ~ 5.6 和 PHP 7.0 的语法规范；\n* 管理员不会合并造成 CI faild 的修改，若出现 CI faild 请检查自己的源代码或修改相应的[单元测试文件](tests)；\n\n## GitHub Issue\n\nGitHub 提供了 Issue 功能，该功能可以用于：\n\n* 提出 bug\n* 提出功能改进\n* 反馈使用体验\n\n该功能不应该用于：\n\n * 提出修改意见（涉及代码署名和修订追溯问题）\n * 不友善的言论\n\n## 快速修改\n\n**GitHub 提供了快速编辑文件的功能**\n\n1. 登录 GitHub 帐号；\n2. 浏览项目文件，找到要进行修改的文件；\n3. 点击右上角铅笔图标进行修改；\n4. 填写 `Commit changes` 相关内容（Title 必填）；\n5. 提交修改，等待 CI 验证和管理员合并。\n\n**若您需要一次提交大量修改，请继续阅读下面的内容**\n\n## 完整流程\n\n1. `fork`本项目；\n2. 克隆(`clone`)你 `fork` 的项目到本地；\n3. 新建分支(`branch`)并检出(`checkout`)新分支；\n4. 添加本项目到你的本地 git 仓库作为上游(`upstream`)；\n5. 进行修改，若你的修改包含方法或函数的增减，请记得修改[单元测试文件](tests)；\n6. 变基（衍合 `rebase`）你的分支到上游 master 分支；\n7. `push` 你的本地仓库到 GitHub；\n8. 提交 `pull request`；\n9. 等待 CI 验证（若不通过则重复 5~7，GitHub 会自动更新你的 `pull request`）；\n10. 等待管理员处理，并及时 `rebase` 你的分支到上游 master 分支（若上游 master 分支有修改）。\n\n*若有必要，可以 `git push -f` 强行推送 rebase 后的分支到自己的 `fork`*\n\n*绝对不可以使用 `git push -f` 强行推送修改到上游*\n\n### 注意事项\n\n* 若对上述流程有任何不清楚的地方，请查阅 GIT 教程，如 [这个](http://backlogtool.com/git-guide/cn/)；\n* 对于代码**不同方面**的修改，请在自己 `fork` 的项目中**创建不同的分支**（原因参见`完整流程`第9条备注部分）；\n* 变基及交互式变基操作参见 [Git 交互式变基](http://pakchoi.me/2015/03/17/git-interactive-rebase/)\n\n## 推荐资源\n\n### 开发环境\n\n* XAMPP for Windows 5.5.x\n* WampServer (for Windows)\n* upupw Apache PHP5.4 ( for Windows)\n\n或自行安装\n\n- Apache / Nginx\n- PHP 5.4 ~ 5.6\n- MySQL / MariaDB\n\n*Windows 用户推荐添加 PHP bin 目录到 PATH，方便使用 composer*\n\n*Linux 用户自行配置环境， Mac 用户推荐使用内置 Apache 配合 Homebrew 安装 PHP 和 MariaDB*\n\n### 编辑器\n\nSublime Text 3 + phpfmt 插件\n\nphpfmt 插件参数\n\n```json\n{\n\t\"autocomplete\": true,\n\t\"enable_auto_align\": true,\n\t\"format_on_save\": true,\n\t\"indent_with_space\": true,\n\t\"psr1_naming\": false,\n\t\"psr2\": true,\n\t\"version\": 4\n}\n```\n\n或其他 编辑器 / IDE 配合 PSR2 自动格式化工具\n\n### Git GUI\n\n* SourceTree\n* GitHub Desktop\n\n或其他 Git 图形界面客户端\n"
  },
  {
    "path": "thinkphp/LICENSE.txt",
    "content": "\nThinkPHP遵循Apache2开源协议发布，并提供免费使用。\n版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)\nAll rights reserved。\nThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。\n\nApache Licence是著名的非盈利开源组织Apache采用的协议。\n该协议和BSD类似，鼓励代码共享和尊重原作者的著作权，\n允许代码修改，再作为开源或商业软件发布。需要满足\n的条件： \n1． 需要给代码的用户一份Apache Licence ；\n2． 如果你修改了代码，需要在被修改的文件中说明；\n3． 在延伸的代码中（修改和有源代码衍生的代码中）需要\n带有原来代码中的协议，商标，专利声明和其他原来作者规\n定需要包含的说明；\n4． 如果再发布的产品中包含一个Notice文件，则在Notice文\n件中需要带有本协议内容。你可以在Notice中增加自己的\n许可，但不可以表现为对Apache Licence构成更改。 \n具体的协议参考：http://www.apache.org/licenses/LICENSE-2.0\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\nFOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\nCOPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\nBUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\nANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "thinkphp/README.md",
    "content": "ThinkPHP 5.0\n===============\n\n[![StyleCI](https://styleci.io/repos/48530411/shield?style=flat&branch=master)](https://styleci.io/repos/48530411)\n[![Build Status](https://travis-ci.org/top-think/framework.svg?branch=master)](https://travis-ci.org/top-think/framework)\n[![codecov.io](http://codecov.io/github/top-think/framework/coverage.svg?branch=master)](http://codecov.io/github/github/top-think/framework?branch=master)\n[![Total Downloads](https://poser.pugx.org/topthink/framework/downloads)](https://packagist.org/packages/topthink/framework)\n[![Latest Stable Version](https://poser.pugx.org/topthink/framework/v/stable)](https://packagist.org/packages/topthink/framework)\n[![Latest Unstable Version](https://poser.pugx.org/topthink/framework/v/unstable)](https://packagist.org/packages/topthink/framework)\n[![License](https://poser.pugx.org/topthink/framework/license)](https://packagist.org/packages/topthink/framework)\n\nThinkPHP5在保持快速开发和大道至简的核心理念不变的同时，PHP版本要求提升到5.4，优化核心，减少依赖，基于全新的架构思想和命名空间实现，是ThinkPHP突破原有框架思路的颠覆之作，其主要特性包括：\n\n + 基于命名空间和众多PHP新特性\n + 核心功能组件化\n + 强化路由功能\n + 更灵活的控制器\n + 重构的模型和数据库类\n + 配置文件可分离\n + 重写的自动验证和完成\n + 简化扩展机制\n + API支持完善\n + 改进的Log类\n + 命令行访问支持\n + REST支持\n + 引导文件支持\n + 方便的自动生成定义\n + 真正惰性加载\n + 分布式环境支持\n + 支持Composer\n + 支持MongoDb\n\n> ThinkPHP5的运行环境要求PHP5.4以上。\n\n详细开发文档参考 [ThinkPHP5完全开发手册](http://www.kancloud.cn/manual/thinkphp5) 以及[ThinkPHP5入门系列教程](http://www.kancloud.cn/special/thinkphp5_quickstart)\n\n## 目录结构\n\n初始的目录结构如下：\n\n~~~\nwww  WEB部署目录（或者子目录）\n├─application           应用目录\n│  ├─common             公共模块目录（可以更改）\n│  ├─module_name        模块目录\n│  │  ├─config.php      模块配置文件\n│  │  ├─common.php      模块函数文件\n│  │  ├─controller      控制器目录\n│  │  ├─model           模型目录\n│  │  ├─view            视图目录\n│  │  └─ ...            更多类库目录\n│  │\n│  ├─command.php        命令行工具配置文件\n│  ├─common.php         公共函数文件\n│  ├─config.php         公共配置文件\n│  ├─route.php          路由配置文件\n│  ├─tags.php           应用行为扩展定义文件\n│  └─database.php       数据库配置文件\n│\n├─public                WEB目录（对外访问目录）\n│  ├─index.php          入口文件\n│  ├─router.php         快速测试文件\n│  └─.htaccess          用于apache的重写\n│\n├─thinkphp              框架系统目录\n│  ├─lang               语言文件目录\n│  ├─library            框架类库目录\n│  │  ├─think           Think类库包目录\n│  │  └─traits          系统Trait目录\n│  │\n│  ├─tpl                系统模板目录\n│  ├─base.php           基础定义文件\n│  ├─console.php        控制台入口文件\n│  ├─convention.php     框架惯例配置文件\n│  ├─helper.php         助手函数文件\n│  ├─phpunit.xml        phpunit配置文件\n│  └─start.php          框架入口文件\n│\n├─extend                扩展类库目录\n├─runtime               应用的运行时目录（可写，可定制）\n├─vendor                第三方类库目录（Composer依赖库）\n├─build.php             自动生成定义文件（参考）\n├─composer.json         composer 定义文件\n├─LICENSE.txt           授权说明文件\n├─README.md             README 文件\n├─think                 命令行入口文件\n~~~\n\n> router.php用于php自带webserver支持，可用于快速测试\n> 切换到public目录后，启动命令：php -S localhost:8888  router.php\n> 上面的目录结构和名称是可以改变的，这取决于你的入口文件和配置参数。\n\n## 命名规范\n\nThinkPHP5的命名规范遵循PSR-2规范以及PSR-4自动加载规范。\n\n## 参与开发\n注册并登录 Github 帐号， fork 本项目并进行改动。\n\n更多细节参阅 [CONTRIBUTING.md](CONTRIBUTING.md)\n\n## 版权信息\n\nThinkPHP遵循Apache2开源协议发布，并提供免费使用。\n\n本项目包含的第三方源码和二进制文件之版权信息另行标注。\n\n版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)\n\nAll rights reserved。\n\nThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。\n\n更多细节参阅 [LICENSE.txt](LICENSE.txt)\n"
  },
  {
    "path": "thinkphp/base.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\ndefine('THINK_VERSION', '5.0.10');\ndefine('THINK_START_TIME', microtime(true));\ndefine('THINK_START_MEM', memory_get_usage());\ndefine('EXT', '.php');\ndefine('DS', DIRECTORY_SEPARATOR);\ndefined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS);\ndefine('LIB_PATH', THINK_PATH . 'library' . DS);\ndefine('CORE_PATH', LIB_PATH . 'think' . DS);\ndefine('TRAIT_PATH', LIB_PATH . 'traits' . DS);\ndefined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . DS);\ndefined('ROOT_PATH') or define('ROOT_PATH', dirname(realpath(APP_PATH)) . DS);\ndefined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS);\ndefined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS);\ndefined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS);\ndefined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS);\ndefined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS);\ndefined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS);\ndefined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录\ndefined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀\ndefined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀\n\n// 环境常量\ndefine('IS_CLI', PHP_SAPI == 'cli' ? true : false);\ndefine('IS_WIN', strpos(PHP_OS, 'WIN') !== false);\n\n// 载入Loader类\nrequire CORE_PATH . 'Loader.php';\n\n// 加载环境变量配置文件\nif (is_file(ROOT_PATH . '.env')) {\n    $env = parse_ini_file(ROOT_PATH . '.env', true);\n    foreach ($env as $key => $val) {\n        $name = ENV_PREFIX . strtoupper($key);\n        if (is_array($val)) {\n            foreach ($val as $k => $v) {\n                $item = $name . '_' . strtoupper($k);\n                putenv(\"$item=$v\");\n            }\n        } else {\n            putenv(\"$name=$val\");\n        }\n    }\n}\n\n// 注册自动加载\n\\think\\Loader::register();\n\n// 注册错误和异常处理机制\n\\think\\Error::register();\n\n// 加载惯例配置文件\n\\think\\Config::set(include THINK_PATH . 'convention' . EXT);\n"
  },
  {
    "path": "thinkphp/codecov.yml",
    "content": "comment:\n  layout: header, changes, diff\ncoverage:\n  ignore:\n  - base.php\n  - helper.php\n  - convention.php\n  - lang/zh-cn.php\n  - start.php\n  - console.php\n  status:\n    patch: false\n"
  },
  {
    "path": "thinkphp/composer.json",
    "content": "{\n    \"name\": \"topthink/framework\",\n    \"description\": \"the new thinkphp framework\",\n    \"type\": \"think-framework\",\n    \"keywords\": [\n        \"framework\",\n        \"thinkphp\",\n        \"ORM\"\n    ],\n    \"homepage\": \"http://thinkphp.cn/\",\n    \"license\": \"Apache-2.0\",\n    \"authors\": [\n        {\n            \"name\": \"liu21st\",\n            \"email\": \"liu21st@gmail.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.4.0\",\n        \"topthink/think-installer\": \"~1.0\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"4.8.*\",\n        \"johnkary/phpunit-speedtrap\": \"^1.0\",\n        \"mikey179/vfsStream\": \"~1.6\",\n        \"phploc/phploc\": \"2.*\",\n        \"sebastian/phpcpd\": \"2.*\",\n        \"phpdocumentor/reflection-docblock\": \"^2.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"think\\\\\": \"library/think\"\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/console.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\n// ThinkPHP 引导文件\n// 加载基础文件\nrequire __DIR__ . '/base.php';\n\n// 执行应用\nApp::initCommon();\nConsole::init();\n"
  },
  {
    "path": "thinkphp/convention.php",
    "content": "<?php\n\nreturn [\n    // +----------------------------------------------------------------------\n    // | 应用设置\n    // +----------------------------------------------------------------------\n    // 默认Host地址\n    'app_host'               => '',\n    // 应用调试模式\n    'app_debug'              => false,\n    // 应用Trace\n    'app_trace'              => false,\n    // 应用模式状态\n    'app_status'             => '',\n    // 是否支持多模块\n    'app_multi_module'       => true,\n    // 入口自动绑定模块\n    'auto_bind_module'       => false,\n    // 注册的根命名空间\n    'root_namespace'         => [],\n    // 扩展函数文件\n    'extra_file_list'        => [THINK_PATH . 'helper' . EXT],\n    // 默认输出类型\n    'default_return_type'    => 'html',\n    // 默认AJAX 数据返回格式,可选json xml ...\n    'default_ajax_return'    => 'json',\n    // 默认JSONP格式返回的处理方法\n    'default_jsonp_handler'  => 'jsonpReturn',\n    // 默认JSONP处理方法\n    'var_jsonp_handler'      => 'callback',\n    // 默认时区\n    'default_timezone'       => 'PRC',\n    // 是否开启多语言\n    'lang_switch_on'         => false,\n    // 默认全局过滤方法 用逗号分隔多个\n    'default_filter'         => '',\n    // 默认语言\n    'default_lang'           => 'zh-cn',\n    // 应用类库后缀\n    'class_suffix'           => false,\n    // 控制器类后缀\n    'controller_suffix'      => false,\n\n    // +----------------------------------------------------------------------\n    // | 模块设置\n    // +----------------------------------------------------------------------\n\n    // 默认模块名\n    'default_module'         => 'index',\n    // 禁止访问模块\n    'deny_module_list'       => ['common'],\n    // 默认控制器名\n    'default_controller'     => 'Index',\n    // 默认操作名\n    'default_action'         => 'index',\n    // 默认验证器\n    'default_validate'       => '',\n    // 默认的空控制器名\n    'empty_controller'       => 'Error',\n    // 操作方法前缀\n    'use_action_prefix'      => false,\n    // 操作方法后缀\n    'action_suffix'          => '',\n    // 自动搜索控制器\n    'controller_auto_search' => false,\n\n    // +----------------------------------------------------------------------\n    // | URL设置\n    // +----------------------------------------------------------------------\n\n    // PATHINFO变量名 用于兼容模式\n    'var_pathinfo'           => 's',\n    // 兼容PATH_INFO获取\n    'pathinfo_fetch'         => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],\n    // pathinfo分隔符\n    'pathinfo_depr'          => '/',\n    // HTTPS代理标识\n    'https_agent_name'       => '',\n    // URL伪静态后缀\n    'url_html_suffix'        => 'html',\n    // URL普通方式参数 用于自动生成\n    'url_common_param'       => false,\n    // URL参数方式 0 按名称成对解析 1 按顺序解析\n    'url_param_type'         => 0,\n    // 是否开启路由\n    'url_route_on'           => true,\n    // 路由配置文件（支持配置多个）\n    'route_config_file'      => ['route'],\n    // 路由使用完整匹配\n    'route_complete_match'   => false,\n    // 是否强制使用路由\n    'url_route_must'         => false,\n    // 域名部署\n    'url_domain_deploy'      => false,\n    // 域名根，如thinkphp.cn\n    'url_domain_root'        => '',\n    // 是否自动转换URL中的控制器和操作名\n    'url_convert'            => true,\n    // 默认的访问控制器层\n    'url_controller_layer'   => 'controller',\n    // 表单请求类型伪装变量\n    'var_method'             => '_method',\n    // 表单ajax伪装变量\n    'var_ajax'               => '_ajax',\n    // 表单pjax伪装变量\n    'var_pjax'               => '_pjax',\n    // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则\n    'request_cache'          => false,\n    // 请求缓存有效期\n    'request_cache_expire'   => null,\n    // 全局请求缓存排除规则\n    'request_cache_except'   => [],\n\n    // +----------------------------------------------------------------------\n    // | 模板设置\n    // +----------------------------------------------------------------------\n\n    'template'               => [\n        // 模板引擎类型 支持 php think 支持扩展\n        'type'         => 'Think',\n        // 视图基础目录，配置目录为所有模块的视图起始目录\n        'view_base'    => '',\n        // 当前模板的视图目录 留空为自动获取\n        'view_path'    => '',\n        // 模板后缀\n        'view_suffix'  => 'html',\n        // 模板文件名分隔符\n        'view_depr'    => DS,\n        // 模板引擎普通标签开始标记\n        'tpl_begin'    => '{',\n        // 模板引擎普通标签结束标记\n        'tpl_end'      => '}',\n        // 标签库标签开始标记\n        'taglib_begin' => '{',\n        // 标签库标签结束标记\n        'taglib_end'   => '}',\n    ],\n\n    // 视图输出字符串内容替换\n    'view_replace_str'       => [],\n    // 默认跳转页面对应的模板文件\n    'dispatch_success_tmpl'  => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',\n    'dispatch_error_tmpl'    => THINK_PATH . 'tpl' . DS . 'dispatch_jump.tpl',\n\n    // +----------------------------------------------------------------------\n    // | 异常及错误设置\n    // +----------------------------------------------------------------------\n\n    // 异常页面的模板文件\n    'exception_tmpl'         => THINK_PATH . 'tpl' . DS . 'think_exception.tpl',\n\n    // 错误显示信息,非调试模式有效\n    'error_message'          => '页面错误！请稍后再试～',\n    // 显示错误信息\n    'show_error_msg'         => false,\n    // 异常处理handle类 留空使用 \\think\\exception\\Handle\n    'exception_handle'       => '',\n\n    // +----------------------------------------------------------------------\n    // | 日志设置\n    // +----------------------------------------------------------------------\n\n    'log'                    => [\n        // 日志记录方式，内置 file socket 支持扩展\n        'type'  => 'File',\n        // 日志保存目录\n        'path'  => LOG_PATH,\n        // 日志记录级别\n        'level' => [],\n    ],\n\n    // +----------------------------------------------------------------------\n    // | Trace设置 开启 app_trace 后 有效\n    // +----------------------------------------------------------------------\n    'trace'                  => [\n        // 内置Html Console 支持扩展\n        'type' => 'Html',\n    ],\n\n    // +----------------------------------------------------------------------\n    // | 缓存设置\n    // +----------------------------------------------------------------------\n\n    'cache'                  => [\n        // 驱动方式\n        'type'   => 'File',\n        // 缓存保存目录\n        'path'   => CACHE_PATH,\n        // 缓存前缀\n        'prefix' => '',\n        // 缓存有效期 0表示永久缓存\n        'expire' => 0,\n    ],\n\n    // +----------------------------------------------------------------------\n    // | 会话设置\n    // +----------------------------------------------------------------------\n\n    'session'                => [\n        'id'             => '',\n        // SESSION_ID的提交变量,解决flash上传跨域\n        'var_session_id' => '',\n        // SESSION 前缀\n        'prefix'         => 'think',\n        // 驱动方式 支持redis memcache memcached\n        'type'           => '',\n        // 是否自动开启 SESSION\n        'auto_start'     => true,\n        'httponly'       => true,\n        'secure'         => false,\n    ],\n\n    // +----------------------------------------------------------------------\n    // | Cookie设置\n    // +----------------------------------------------------------------------\n    'cookie'                 => [\n        // cookie 名称前缀\n        'prefix'    => '',\n        // cookie 保存时间\n        'expire'    => 0,\n        // cookie 保存路径\n        'path'      => '/',\n        // cookie 有效域名\n        'domain'    => '',\n        //  cookie 启用安全传输\n        'secure'    => false,\n        // httponly设置\n        'httponly'  => '',\n        // 是否使用 setcookie\n        'setcookie' => true,\n    ],\n\n    // +----------------------------------------------------------------------\n    // | 数据库设置\n    // +----------------------------------------------------------------------\n\n    'database'               => [\n        // 数据库类型\n        'type'            => 'mysql',\n        // 数据库连接DSN配置\n        'dsn'             => '',\n        // 服务器地址\n        'hostname'        => '127.0.0.1',\n        // 数据库名\n        'database'        => '',\n        // 数据库用户名\n        'username'        => 'root',\n        // 数据库密码\n        'password'        => '',\n        // 数据库连接端口\n        'hostport'        => '',\n        // 数据库连接参数\n        'params'          => [],\n        // 数据库编码默认采用utf8\n        'charset'         => 'utf8',\n        // 数据库表前缀\n        'prefix'          => '',\n        // 数据库调试模式\n        'debug'           => false,\n        // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)\n        'deploy'          => 0,\n        // 数据库读写是否分离 主从式有效\n        'rw_separate'     => false,\n        // 读写分离后 主服务器数量\n        'master_num'      => 1,\n        // 指定从服务器序号\n        'slave_no'        => '',\n        // 是否严格检查字段是否存在\n        'fields_strict'   => true,\n        // 数据集返回类型\n        'resultset_type'  => 'array',\n        // 自动写入时间戳字段\n        'auto_timestamp'  => false,\n        // 时间字段取出后的默认时间格式\n        'datetime_format' => 'Y-m-d H:i:s',\n        // 是否需要进行SQL性能分析\n        'sql_explain'     => false,\n    ],\n\n    //分页配置\n    'paginate'               => [\n        'type'      => 'bootstrap',\n        'var_page'  => 'page',\n        'list_rows' => 15,\n    ],\n\n];\n"
  },
  {
    "path": "thinkphp/helper.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n//------------------------\n// ThinkPHP 助手函数\n//-------------------------\n\nuse think\\Cache;\nuse think\\Config;\nuse think\\Cookie;\nuse think\\Db;\nuse think\\Debug;\nuse think\\exception\\HttpException;\nuse think\\exception\\HttpResponseException;\nuse think\\Lang;\nuse think\\Loader;\nuse think\\Log;\nuse think\\Model;\nuse think\\Request;\nuse think\\Response;\nuse think\\Session;\nuse think\\Url;\nuse think\\View;\n\nif (!function_exists('load_trait')) {\n    /**\n     * 快速导入Traits PHP5.5以上无需调用\n     * @param string    $class trait库\n     * @param string    $ext 类库后缀\n     * @return boolean\n     */\n    function load_trait($class, $ext = EXT)\n    {\n        return Loader::import($class, TRAIT_PATH, $ext);\n    }\n}\n\nif (!function_exists('exception')) {\n    /**\n     * 抛出异常处理\n     *\n     * @param string    $msg  异常消息\n     * @param integer   $code 异常代码 默认为0\n     * @param string    $exception 异常类\n     *\n     * @throws Exception\n     */\n    function exception($msg, $code = 0, $exception = '')\n    {\n        $e = $exception ?: '\\think\\Exception';\n        throw new $e($msg, $code);\n    }\n}\n\nif (!function_exists('debug')) {\n    /**\n     * 记录时间（微秒）和内存使用情况\n     * @param string            $start 开始标签\n     * @param string            $end 结束标签\n     * @param integer|string    $dec 小数位 如果是m 表示统计内存占用\n     * @return mixed\n     */\n    function debug($start, $end = '', $dec = 6)\n    {\n        if ('' == $end) {\n            Debug::remark($start);\n        } else {\n            return 'm' == $dec ? Debug::getRangeMem($start, $end) : Debug::getRangeTime($start, $end, $dec);\n        }\n    }\n}\n\nif (!function_exists('lang')) {\n    /**\n     * 获取语言变量值\n     * @param string    $name 语言变量名\n     * @param array     $vars 动态变量值\n     * @param string    $lang 语言\n     * @return mixed\n     */\n    function lang($name, $vars = [], $lang = '')\n    {\n        return Lang::get($name, $vars, $lang);\n    }\n}\n\nif (!function_exists('config')) {\n    /**\n     * 获取和设置配置参数\n     * @param string|array  $name 参数名\n     * @param mixed         $value 参数值\n     * @param string        $range 作用域\n     * @return mixed\n     */\n    function config($name = '', $value = null, $range = '')\n    {\n        if (is_null($value) && is_string($name)) {\n            return 0 === strpos($name, '?') ? Config::has(substr($name, 1), $range) : Config::get($name, $range);\n        } else {\n            return Config::set($name, $value, $range);\n        }\n    }\n}\n\nif (!function_exists('input')) {\n    /**\n     * 获取输入数据 支持默认值和过滤\n     * @param string    $key 获取的变量名\n     * @param mixed     $default 默认值\n     * @param string    $filter 过滤方法\n     * @return mixed\n     */\n    function input($key = '', $default = null, $filter = '')\n    {\n        if (0 === strpos($key, '?')) {\n            $key = substr($key, 1);\n            $has = true;\n        }\n        if ($pos = strpos($key, '.')) {\n            // 指定参数来源\n            list($method, $key) = explode('.', $key, 2);\n            if (!in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) {\n                $key    = $method . '.' . $key;\n                $method = 'param';\n            }\n        } else {\n            // 默认为自动判断\n            $method = 'param';\n        }\n        if (isset($has)) {\n            return request()->has($key, $method, $default);\n        } else {\n            return request()->$method($key, $default, $filter);\n        }\n    }\n}\n\nif (!function_exists('widget')) {\n    /**\n     * 渲染输出Widget\n     * @param string    $name Widget名称\n     * @param array     $data 传入的参数\n     * @return mixed\n     */\n    function widget($name, $data = [])\n    {\n        return Loader::action($name, $data, 'widget');\n    }\n}\n\nif (!function_exists('model')) {\n    /**\n     * 实例化Model\n     * @param string    $name Model名称\n     * @param string    $layer 业务层名称\n     * @param bool      $appendSuffix 是否添加类名后缀\n     * @return \\think\\Model\n     */\n    function model($name = '', $layer = 'model', $appendSuffix = false)\n    {\n        return Loader::model($name, $layer, $appendSuffix);\n    }\n}\n\nif (!function_exists('validate')) {\n    /**\n     * 实例化验证器\n     * @param string    $name 验证器名称\n     * @param string    $layer 业务层名称\n     * @param bool      $appendSuffix 是否添加类名后缀\n     * @return \\think\\Validate\n     */\n    function validate($name = '', $layer = 'validate', $appendSuffix = false)\n    {\n        return Loader::validate($name, $layer, $appendSuffix);\n    }\n}\n\nif (!function_exists('db')) {\n    /**\n     * 实例化数据库类\n     * @param string        $name 操作的数据表名称（不含前缀）\n     * @param array|string  $config 数据库配置参数\n     * @param bool          $force 是否强制重新连接\n     * @return \\think\\db\\Query\n     */\n    function db($name = '', $config = [], $force = false)\n    {\n        return Db::connect($config, $force)->name($name);\n    }\n}\n\nif (!function_exists('controller')) {\n    /**\n     * 实例化控制器 格式：[模块/]控制器\n     * @param string    $name 资源地址\n     * @param string    $layer 控制层名称\n     * @param bool      $appendSuffix 是否添加类名后缀\n     * @return \\think\\Controller\n     */\n    function controller($name, $layer = 'controller', $appendSuffix = false)\n    {\n        return Loader::controller($name, $layer, $appendSuffix);\n    }\n}\n\nif (!function_exists('action')) {\n    /**\n     * 调用模块的操作方法 参数格式 [模块/控制器/]操作\n     * @param string        $url 调用地址\n     * @param string|array  $vars 调用参数 支持字符串和数组\n     * @param string        $layer 要调用的控制层名称\n     * @param bool          $appendSuffix 是否添加类名后缀\n     * @return mixed\n     */\n    function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)\n    {\n        return Loader::action($url, $vars, $layer, $appendSuffix);\n    }\n}\n\nif (!function_exists('import')) {\n    /**\n     * 导入所需的类库 同java的Import 本函数有缓存功能\n     * @param string    $class 类库命名空间字符串\n     * @param string    $baseUrl 起始路径\n     * @param string    $ext 导入的文件扩展名\n     * @return boolean\n     */\n    function import($class, $baseUrl = '', $ext = EXT)\n    {\n        return Loader::import($class, $baseUrl, $ext);\n    }\n}\n\nif (!function_exists('vendor')) {\n    /**\n     * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面\n     * @param string    $class 类库\n     * @param string    $ext 类库后缀\n     * @return boolean\n     */\n    function vendor($class, $ext = EXT)\n    {\n        return Loader::import($class, VENDOR_PATH, $ext);\n    }\n}\n\nif (!function_exists('dump')) {\n    /**\n     * 浏览器友好的变量输出\n     * @param mixed     $var 变量\n     * @param boolean   $echo 是否输出 默认为true 如果为false 则返回输出字符串\n     * @param string    $label 标签 默认为空\n     * @return void|string\n     */\n    function dump($var, $echo = true, $label = null)\n    {\n        return Debug::dump($var, $echo, $label);\n    }\n}\n\nif (!function_exists('url')) {\n    /**\n     * Url生成\n     * @param string        $url 路由地址\n     * @param string|array  $vars 变量\n     * @param bool|string   $suffix 生成的URL后缀\n     * @param bool|string   $domain 域名\n     * @return string\n     */\n    function url($url = '', $vars = '', $suffix = true, $domain = false)\n    {\n        return Url::build($url, $vars, $suffix, $domain);\n    }\n}\n\nif (!function_exists('session')) {\n    /**\n     * Session管理\n     * @param string|array  $name session名称，如果为数组表示进行session设置\n     * @param mixed         $value session值\n     * @param string        $prefix 前缀\n     * @return mixed\n     */\n    function session($name, $value = '', $prefix = null)\n    {\n        if (is_array($name)) {\n            // 初始化\n            Session::init($name);\n        } elseif (is_null($name)) {\n            // 清除\n            Session::clear('' === $value ? null : $value);\n        } elseif ('' === $value) {\n            // 判断或获取\n            return 0 === strpos($name, '?') ? Session::has(substr($name, 1), $prefix) : Session::get($name, $prefix);\n        } elseif (is_null($value)) {\n            // 删除\n            return Session::delete($name, $prefix);\n        } else {\n            // 设置\n            return Session::set($name, $value, $prefix);\n        }\n    }\n}\n\nif (!function_exists('cookie')) {\n    /**\n     * Cookie管理\n     * @param string|array  $name cookie名称，如果为数组表示进行cookie设置\n     * @param mixed         $value cookie值\n     * @param mixed         $option 参数\n     * @return mixed\n     */\n    function cookie($name, $value = '', $option = null)\n    {\n        if (is_array($name)) {\n            // 初始化\n            Cookie::init($name);\n        } elseif (is_null($name)) {\n            // 清除\n            Cookie::clear($value);\n        } elseif ('' === $value) {\n            // 获取\n            return 0 === strpos($name, '?') ? Cookie::has(substr($name, 1), $option) : Cookie::get($name, $option);\n        } elseif (is_null($value)) {\n            // 删除\n            return Cookie::delete($name);\n        } else {\n            // 设置\n            return Cookie::set($name, $value, $option);\n        }\n    }\n}\n\nif (!function_exists('cache')) {\n    /**\n     * 缓存管理\n     * @param mixed     $name 缓存名称，如果为数组表示进行缓存设置\n     * @param mixed     $value 缓存值\n     * @param mixed     $options 缓存参数\n     * @param string    $tag 缓存标签\n     * @return mixed\n     */\n    function cache($name, $value = '', $options = null, $tag = null)\n    {\n        if (is_array($options)) {\n            // 缓存操作的同时初始化\n            $cache = Cache::connect($options);\n        } elseif (is_array($name)) {\n            // 缓存初始化\n            return Cache::connect($name);\n        } else {\n            $cache = Cache::init();\n        }\n\n        if (is_null($name)) {\n            return $cache->clear($value);\n        } elseif ('' === $value) {\n            // 获取缓存\n            return 0 === strpos($name, '?') ? $cache->has(substr($name, 1)) : $cache->get($name);\n        } elseif (is_null($value)) {\n            // 删除缓存\n            return $cache->rm($name);\n        } elseif (0 === strpos($name, '?') && '' !== $value) {\n            $expire = is_numeric($options) ? $options : null;\n            return $cache->remember(substr($name, 1), $value, $expire);\n        } else {\n            // 缓存数据\n            if (is_array($options)) {\n                $expire = isset($options['expire']) ? $options['expire'] : null; //修复查询缓存无法设置过期时间\n            } else {\n                $expire = is_numeric($options) ? $options : null; //默认快捷缓存设置过期时间\n            }\n            if (is_null($tag)) {\n                return $cache->set($name, $value, $expire);\n            } else {\n                return $cache->tag($tag)->set($name, $value, $expire);\n            }\n        }\n    }\n}\n\nif (!function_exists('trace')) {\n    /**\n     * 记录日志信息\n     * @param mixed     $log log信息 支持字符串和数组\n     * @param string    $level 日志级别\n     * @return void|array\n     */\n    function trace($log = '[think]', $level = 'log')\n    {\n        if ('[think]' === $log) {\n            return Log::getLog();\n        } else {\n            Log::record($log, $level);\n        }\n    }\n}\n\nif (!function_exists('request')) {\n    /**\n     * 获取当前Request对象实例\n     * @return Request\n     */\n    function request()\n    {\n        return Request::instance();\n    }\n}\n\nif (!function_exists('response')) {\n    /**\n     * 创建普通 Response 对象实例\n     * @param mixed      $data   输出数据\n     * @param int|string $code   状态码\n     * @param array      $header 头信息\n     * @param string     $type\n     * @return Response\n     */\n    function response($data = [], $code = 200, $header = [], $type = 'html')\n    {\n        return Response::create($data, $type, $code, $header);\n    }\n}\n\nif (!function_exists('view')) {\n    /**\n     * 渲染模板输出\n     * @param string    $template 模板文件\n     * @param array     $vars 模板变量\n     * @param array     $replace 模板替换\n     * @param integer   $code 状态码\n     * @return \\think\\response\\View\n     */\n    function view($template = '', $vars = [], $replace = [], $code = 200)\n    {\n        return Response::create($template, 'view', $code)->replace($replace)->assign($vars);\n    }\n}\n\nif (!function_exists('json')) {\n    /**\n     * 获取\\think\\response\\Json对象实例\n     * @param mixed   $data 返回的数据\n     * @param integer $code 状态码\n     * @param array   $header 头部\n     * @param array   $options 参数\n     * @return \\think\\response\\Json\n     */\n    function json($data = [], $code = 200, $header = [], $options = [])\n    {\n        return Response::create($data, 'json', $code, $header, $options);\n    }\n}\n\nif (!function_exists('jsonp')) {\n    /**\n     * 获取\\think\\response\\Jsonp对象实例\n     * @param mixed   $data    返回的数据\n     * @param integer $code    状态码\n     * @param array   $header 头部\n     * @param array   $options 参数\n     * @return \\think\\response\\Jsonp\n     */\n    function jsonp($data = [], $code = 200, $header = [], $options = [])\n    {\n        return Response::create($data, 'jsonp', $code, $header, $options);\n    }\n}\n\nif (!function_exists('xml')) {\n    /**\n     * 获取\\think\\response\\Xml对象实例\n     * @param mixed   $data    返回的数据\n     * @param integer $code    状态码\n     * @param array   $header  头部\n     * @param array   $options 参数\n     * @return \\think\\response\\Xml\n     */\n    function xml($data = [], $code = 200, $header = [], $options = [])\n    {\n        return Response::create($data, 'xml', $code, $header, $options);\n    }\n}\n\nif (!function_exists('redirect')) {\n    /**\n     * 获取\\think\\response\\Redirect对象实例\n     * @param mixed         $url 重定向地址 支持Url::build方法的地址\n     * @param array|integer $params 额外参数\n     * @param integer       $code 状态码\n     * @param array         $with 隐式传参\n     * @return \\think\\response\\Redirect\n     */\n    function redirect($url = [], $params = [], $code = 302, $with = [])\n    {\n        if (is_integer($params)) {\n            $code   = $params;\n            $params = [];\n        }\n        return Response::create($url, 'redirect', $code)->params($params)->with($with);\n    }\n}\n\nif (!function_exists('abort')) {\n    /**\n     * 抛出HTTP异常\n     * @param integer|Response      $code 状态码 或者 Response对象实例\n     * @param string                $message 错误信息\n     * @param array                 $header 参数\n     */\n    function abort($code, $message = null, $header = [])\n    {\n        if ($code instanceof Response) {\n            throw new HttpResponseException($code);\n        } else {\n            throw new HttpException($code, $message, null, $header);\n        }\n    }\n}\n\nif (!function_exists('halt')) {\n    /**\n     * 调试变量并且中断输出\n     * @param mixed      $var 调试变量或者信息\n     */\n    function halt($var)\n    {\n        dump($var);\n        throw new HttpResponseException(new Response);\n    }\n}\n\nif (!function_exists('token')) {\n    /**\n     * 生成表单令牌\n     * @param string $name 令牌名称\n     * @param mixed  $type 令牌生成方法\n     * @return string\n     */\n    function token($name = '__token__', $type = 'md5')\n    {\n        $token = Request::instance()->token($name, $type);\n        return '<input type=\"hidden\" name=\"' . $name . '\" value=\"' . $token . '\" />';\n    }\n}\n\nif (!function_exists('load_relation')) {\n    /**\n     * 延迟预载入关联查询\n     * @param mixed $resultSet 数据集\n     * @param mixed $relation 关联\n     * @return array\n     */\n    function load_relation($resultSet, $relation)\n    {\n        $item = current($resultSet);\n        if ($item instanceof Model) {\n            $item->eagerlyResultSet($resultSet, $relation);\n        }\n        return $resultSet;\n    }\n}\n\nif (!function_exists('collection')) {\n    /**\n     * 数组转换为数据集对象\n     * @param array $resultSet 数据集数组\n     * @return \\think\\model\\Collection|\\think\\Collection\n     */\n    function collection($resultSet)\n    {\n        $item = current($resultSet);\n        if ($item instanceof Model) {\n            return \\think\\model\\Collection::make($resultSet);\n        } else {\n            return \\think\\Collection::make($resultSet);\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/lang/zh-cn.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n// 核心中文语言包\nreturn [\n    // 系统错误提示\n    'Undefined variable'        => '未定义变量',\n    'Undefined index'           => '未定义数组索引',\n    'Undefined offset'          => '未定义数组下标',\n    'Parse error'               => '语法解析错误',\n    'Type error'                => '类型错误',\n    'Fatal error'               => '致命错误',\n    'syntax error'              => '语法错误',\n\n    // 框架核心错误提示\n    'dispatch type not support' => '不支持的调度类型',\n    'method param miss'         => '方法参数错误',\n    'method not exists'         => '方法不存在',\n    'module not exists'         => '模块不存在',\n    'controller not exists'     => '控制器不存在',\n    'class not exists'          => '类不存在',\n    'property not exists'       => '类的属性不存在',\n    'template not exists'       => '模板文件不存在',\n    'illegal controller name'   => '非法的控制器名称',\n    'illegal action name'       => '非法的操作名称',\n    'url suffix deny'           => '禁止的URL后缀访问',\n    'Route Not Found'           => '当前访问路由未定义',\n    'Undefined db type'         => '未定义数据库类型',\n    'variable type error'       => '变量类型错误',\n    'PSR-4 error'               => 'PSR-4 规范错误',\n    'not support total'         => '简洁模式下不能获取数据总数',\n    'not support last'          => '简洁模式下不能获取最后一页',\n    'error session handler'     => '错误的SESSION处理器类',\n    'not allow php tag'         => '模板不允许使用PHP语法',\n    'not support'               => '不支持',\n    'redisd master'             => 'Redisd 主服务器错误',\n    'redisd slave'              => 'Redisd 从服务器错误',\n    'must run at sae'           => '必须在SAE运行',\n    'memcache init error'       => '未开通Memcache服务，请在SAE管理平台初始化Memcache服务',\n    'KVDB init error'           => '没有初始化KVDB，请在SAE管理平台初始化KVDB服务',\n    'fields not exists'         => '数据表字段不存在',\n    'where express error'       => '查询表达式错误',\n    'no data to update'         => '没有任何数据需要更新',\n    'miss data to insert'       => '缺少需要写入的数据',\n    'miss complex primary data' => '缺少复合主键数据',\n    'miss update condition'     => '缺少更新条件',\n    'model data Not Found'      => '模型数据不存在',\n    'table data not Found'      => '表数据不存在',\n    'delete without condition'  => '没有条件不会执行删除操作',\n    'miss relation data'        => '缺少关联表数据',\n    'tag attr must'             => '模板标签属性必须',\n    'tag error'                 => '模板标签错误',\n    'cache write error'         => '缓存写入失败',\n    'sae mc write error'        => 'SAE mc 写入错误',\n    'route name not exists'     => '路由标识不存在（或参数不够）',\n    'invalid request'           => '非法请求',\n    'bind attr has exists'      => '模型的属性已经存在',\n    'relation data not exists'  => '关联数据不存在',\n    'relation not support'      => '关联不支持',\n];\n"
  },
  {
    "path": "thinkphp/library/think/App.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\exception\\HttpException;\nuse think\\exception\\HttpResponseException;\nuse think\\exception\\RouteNotFoundException;\n\n/**\n * App 应用管理\n * @author  liu21st <liu21st@gmail.com>\n */\nclass App\n{\n    /**\n     * @var bool 是否初始化过\n     */\n    protected static $init = false;\n\n    /**\n     * @var string 当前模块路径\n     */\n    public static $modulePath;\n\n    /**\n     * @var bool 应用调试模式\n     */\n    public static $debug = true;\n\n    /**\n     * @var string 应用类库命名空间\n     */\n    public static $namespace = 'app';\n\n    /**\n     * @var bool 应用类库后缀\n     */\n    public static $suffix = false;\n\n    /**\n     * @var bool 应用路由检测\n     */\n    protected static $routeCheck;\n\n    /**\n     * @var bool 严格路由检测\n     */\n    protected static $routeMust;\n\n    protected static $dispatch;\n    protected static $file = [];\n\n    /**\n     * 执行应用程序\n     * @access public\n     * @param Request $request Request对象\n     * @return Response\n     * @throws Exception\n     */\n    public static function run(Request $request = null)\n    {\n        is_null($request) && $request = Request::instance();\n\n        try {\n            $config = self::initCommon();\n            if (defined('BIND_MODULE')) {\n                // 模块/控制器绑定\n                BIND_MODULE && Route::bind(BIND_MODULE);\n            } elseif ($config['auto_bind_module']) {\n                // 入口自动绑定\n                $name = pathinfo($request->baseFile(), PATHINFO_FILENAME);\n                if ($name && 'index' != $name && is_dir(APP_PATH . $name)) {\n                    Route::bind($name);\n                }\n            }\n\n            $request->filter($config['default_filter']);\n\n            // 默认语言\n            Lang::range($config['default_lang']);\n            if ($config['lang_switch_on']) {\n                // 开启多语言机制 检测当前语言\n                Lang::detect();\n            }\n            $request->langset(Lang::range());\n\n            // 加载系统语言包\n            Lang::load([\n                THINK_PATH . 'lang' . DS . $request->langset() . EXT,\n                APP_PATH . 'lang' . DS . $request->langset() . EXT,\n            ]);\n\n            // 获取应用调度信息\n            $dispatch = self::$dispatch;\n            if (empty($dispatch)) {\n                // 进行URL路由检测\n                $dispatch = self::routeCheck($request, $config);\n            }\n            // 记录当前调度信息\n            $request->dispatch($dispatch);\n\n            // 记录路由和请求信息\n            if (self::$debug) {\n                Log::record('[ ROUTE ] ' . var_export($dispatch, true), 'info');\n                Log::record('[ HEADER ] ' . var_export($request->header(), true), 'info');\n                Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info');\n            }\n\n            // 监听app_begin\n            Hook::listen('app_begin', $dispatch);\n            // 请求缓存检查\n            $request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']);\n\n            $data = self::exec($dispatch, $config);\n        } catch (HttpResponseException $exception) {\n            $data = $exception->getResponse();\n        }\n\n        // 清空类的实例化\n        Loader::clearInstance();\n\n        // 输出数据到客户端\n        if ($data instanceof Response) {\n            $response = $data;\n        } elseif (!is_null($data)) {\n            // 默认自动识别响应输出类型\n            $isAjax   = $request->isAjax();\n            $type     = $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type');\n            $response = Response::create($data, $type);\n        } else {\n            $response = Response::create();\n        }\n\n        // 监听app_end\n        Hook::listen('app_end', $response);\n\n        return $response;\n    }\n\n    /**\n     * 设置当前请求的调度信息\n     * @access public\n     * @param array|string  $dispatch 调度信息\n     * @param string        $type 调度类型\n     * @return void\n     */\n    public static function dispatch($dispatch, $type = 'module')\n    {\n        self::$dispatch = ['type' => $type, $type => $dispatch];\n    }\n\n    /**\n     * 执行函数或者闭包方法 支持参数调用\n     * @access public\n     * @param string|array|\\Closure $function 函数或者闭包\n     * @param array                 $vars     变量\n     * @return mixed\n     */\n    public static function invokeFunction($function, $vars = [])\n    {\n        $reflect = new \\ReflectionFunction($function);\n        $args    = self::bindParams($reflect, $vars);\n        // 记录执行信息\n        self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');\n        return $reflect->invokeArgs($args);\n    }\n\n    /**\n     * 调用反射执行类的方法 支持参数绑定\n     * @access public\n     * @param string|array $method 方法\n     * @param array        $vars   变量\n     * @return mixed\n     */\n    public static function invokeMethod($method, $vars = [])\n    {\n        if (is_array($method)) {\n            $class   = is_object($method[0]) ? $method[0] : self::invokeClass($method[0]);\n            $reflect = new \\ReflectionMethod($class, $method[1]);\n        } else {\n            // 静态方法\n            $reflect = new \\ReflectionMethod($method);\n        }\n        $args = self::bindParams($reflect, $vars);\n\n        self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info');\n        return $reflect->invokeArgs(isset($class) ? $class : null, $args);\n    }\n\n    /**\n     * 调用反射执行类的实例化 支持依赖注入\n     * @access public\n     * @param string    $class 类名\n     * @param array     $vars  变量\n     * @return mixed\n     */\n    public static function invokeClass($class, $vars = [])\n    {\n        $reflect     = new \\ReflectionClass($class);\n        $constructor = $reflect->getConstructor();\n        if ($constructor) {\n            $args = self::bindParams($constructor, $vars);\n        } else {\n            $args = [];\n        }\n        return $reflect->newInstanceArgs($args);\n    }\n\n    /**\n     * 绑定参数\n     * @access private\n     * @param \\ReflectionMethod|\\ReflectionFunction $reflect 反射类\n     * @param array                                 $vars    变量\n     * @return array\n     */\n    private static function bindParams($reflect, $vars = [])\n    {\n        if (empty($vars)) {\n            // 自动获取请求变量\n            if (Config::get('url_param_type')) {\n                $vars = Request::instance()->route();\n            } else {\n                $vars = Request::instance()->param();\n            }\n        }\n        $args = [];\n        if ($reflect->getNumberOfParameters() > 0) {\n            // 判断数组类型 数字数组时按顺序绑定参数\n            reset($vars);\n            $type   = key($vars) === 0 ? 1 : 0;\n            $params = $reflect->getParameters();\n            foreach ($params as $param) {\n                $args[] = self::getParamValue($param, $vars, $type);\n            }\n        }\n        return $args;\n    }\n\n    /**\n     * 获取参数值\n     * @access private\n     * @param \\ReflectionParameter  $param\n     * @param array                 $vars    变量\n     * @param string                $type\n     * @return array\n     */\n    private static function getParamValue($param, &$vars, $type)\n    {\n        $name  = $param->getName();\n        $class = $param->getClass();\n        if ($class) {\n            $className = $class->getName();\n            $bind      = Request::instance()->$name;\n            if ($bind instanceof $className) {\n                $result = $bind;\n            } else {\n                if (method_exists($className, 'invoke')) {\n                    $method = new \\ReflectionMethod($className, 'invoke');\n                    if ($method->isPublic() && $method->isStatic()) {\n                        return $className::invoke(Request::instance());\n                    }\n                }\n                $result = method_exists($className, 'instance') ? $className::instance() : new $className;\n            }\n        } elseif (1 == $type && !empty($vars)) {\n            $result = array_shift($vars);\n        } elseif (0 == $type && isset($vars[$name])) {\n            $result = $vars[$name];\n        } elseif ($param->isDefaultValueAvailable()) {\n            $result = $param->getDefaultValue();\n        } else {\n            throw new \\InvalidArgumentException('method param miss:' . $name);\n        }\n        return $result;\n    }\n\n    protected static function exec($dispatch, $config)\n    {\n        switch ($dispatch['type']) {\n            case 'redirect':\n                // 执行重定向跳转\n                $data = Response::create($dispatch['url'], 'redirect')->code($dispatch['status']);\n                break;\n            case 'module':\n                // 模块/控制器/操作\n                $data = self::module($dispatch['module'], $config, isset($dispatch['convert']) ? $dispatch['convert'] : null);\n                break;\n            case 'controller':\n                // 执行控制器操作\n                $vars = array_merge(Request::instance()->param(), $dispatch['var']);\n                $data = Loader::action($dispatch['controller'], $vars, $config['url_controller_layer'], $config['controller_suffix']);\n                break;\n            case 'method':\n                // 执行回调方法\n                $vars = array_merge(Request::instance()->param(), $dispatch['var']);\n                $data = self::invokeMethod($dispatch['method'], $vars);\n                break;\n            case 'function':\n                // 执行闭包\n                $data = self::invokeFunction($dispatch['function']);\n                break;\n            case 'response':\n                $data = $dispatch['response'];\n                break;\n            default:\n                throw new \\InvalidArgumentException('dispatch type not support');\n        }\n        return $data;\n    }\n\n    /**\n     * 执行模块\n     * @access public\n     * @param array $result 模块/控制器/操作\n     * @param array $config 配置参数\n     * @param bool  $convert 是否自动转换控制器和操作名\n     * @return mixed\n     */\n    public static function module($result, $config, $convert = null)\n    {\n        if (is_string($result)) {\n            $result = explode('/', $result);\n        }\n        $request = Request::instance();\n        if ($config['app_multi_module']) {\n            // 多模块部署\n            $module    = strip_tags(strtolower($result[0] ?: $config['default_module']));\n            $bind      = Route::getBind('module');\n            $available = false;\n            if ($bind) {\n                // 绑定模块\n                list($bindModule) = explode('/', $bind);\n                if (empty($result[0])) {\n                    $module    = $bindModule;\n                    $available = true;\n                } elseif ($module == $bindModule) {\n                    $available = true;\n                }\n            } elseif (!in_array($module, $config['deny_module_list']) && is_dir(APP_PATH . $module)) {\n                $available = true;\n            }\n\n            // 模块初始化\n            if ($module && $available) {\n                // 初始化模块\n                $request->module($module);\n                $config = self::init($module);\n                // 模块请求缓存检查\n                $request->cache($config['request_cache'], $config['request_cache_expire'], $config['request_cache_except']);\n            } else {\n                throw new HttpException(404, 'module not exists:' . $module);\n            }\n        } else {\n            // 单一模块部署\n            $module = '';\n            $request->module($module);\n        }\n        // 当前模块路径\n        App::$modulePath = APP_PATH . ($module ? $module . DS : '');\n\n        // 是否自动转换控制器和操作名\n        $convert = is_bool($convert) ? $convert : $config['url_convert'];\n        // 获取控制器名\n        $controller = strip_tags($result[1] ?: $config['default_controller']);\n        $controller = $convert ? strtolower($controller) : $controller;\n\n        // 获取操作名\n        $actionName = strip_tags($result[2] ?: $config['default_action']);\n        $actionName = $convert ? strtolower($actionName) : $actionName;\n\n        // 设置当前请求的控制器、操作\n        $request->controller(Loader::parseName($controller, 1))->action($actionName);\n\n        // 监听module_init\n        Hook::listen('module_init', $request);\n\n        $instance = Loader::controller($controller, $config['url_controller_layer'], $config['controller_suffix'], $config['empty_controller']);\n        if (is_null($instance)) {\n            throw new HttpException(404, 'controller not exists:' . Loader::parseName($controller, 1));\n        }\n        // 获取当前操作名\n        $action = $actionName . $config['action_suffix'];\n\n        $vars = [];\n        if (is_callable([$instance, $action])) {\n            // 执行操作方法\n            $call = [$instance, $action];\n        } elseif (is_callable([$instance, '_empty'])) {\n            // 空操作\n            $call = [$instance, '_empty'];\n            $vars = [$actionName];\n        } else {\n            // 操作不存在\n            throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');\n        }\n\n        Hook::listen('action_begin', $call);\n\n        return self::invokeMethod($call, $vars);\n    }\n\n    /**\n     * 初始化应用\n     */\n    public static function initCommon()\n    {\n        if (empty(self::$init)) {\n            if (defined('APP_NAMESPACE')) {\n                self::$namespace = APP_NAMESPACE;\n            }\n            Loader::addNamespace(self::$namespace, APP_PATH);\n\n            // 初始化应用\n            $config       = self::init();\n            self::$suffix = $config['class_suffix'];\n\n            // 应用调试模式\n            self::$debug = Env::get('app_debug', Config::get('app_debug'));\n            if (!self::$debug) {\n                ini_set('display_errors', 'Off');\n            } elseif (!IS_CLI) {\n                //重新申请一块比较大的buffer\n                if (ob_get_level() > 0) {\n                    $output = ob_get_clean();\n                }\n                ob_start();\n                if (!empty($output)) {\n                    echo $output;\n                }\n            }\n\n            if (!empty($config['root_namespace'])) {\n                Loader::addNamespace($config['root_namespace']);\n            }\n\n            // 加载额外文件\n            if (!empty($config['extra_file_list'])) {\n                foreach ($config['extra_file_list'] as $file) {\n                    $file = strpos($file, '.') ? $file : APP_PATH . $file . EXT;\n                    if (is_file($file) && !isset(self::$file[$file])) {\n                        include $file;\n                        self::$file[$file] = true;\n                    }\n                }\n            }\n\n            // 设置系统时区\n            date_default_timezone_set($config['default_timezone']);\n\n            // 监听app_init\n            Hook::listen('app_init');\n\n            self::$init = true;\n        }\n        return Config::get();\n    }\n\n    /**\n     * 初始化应用或模块\n     * @access public\n     * @param string $module 模块名\n     * @return array\n     */\n    private static function init($module = '')\n    {\n        // 定位模块目录\n        $module = $module ? $module . DS : '';\n\n        // 加载初始化文件\n        if (is_file(APP_PATH . $module . 'init' . EXT)) {\n            include APP_PATH . $module . 'init' . EXT;\n        } elseif (is_file(RUNTIME_PATH . $module . 'init' . EXT)) {\n            include RUNTIME_PATH . $module . 'init' . EXT;\n        } else {\n            $path = APP_PATH . $module;\n            // 加载模块配置\n            $config = Config::load(CONF_PATH . $module . 'config' . CONF_EXT);\n            // 读取数据库配置文件\n            $filename = CONF_PATH . $module . 'database' . CONF_EXT;\n            Config::load($filename, 'database');\n            // 读取扩展配置文件\n            if (is_dir(CONF_PATH . $module . 'extra')) {\n                $dir   = CONF_PATH . $module . 'extra';\n                $files = scandir($dir);\n                foreach ($files as $file) {\n                    if ('.' . pathinfo($file, PATHINFO_EXTENSION) === CONF_EXT) {\n                        $filename = $dir . DS . $file;\n                        Config::load($filename, pathinfo($file, PATHINFO_FILENAME));\n                    }\n                }\n            }\n\n            // 加载应用状态配置\n            if ($config['app_status']) {\n                $config = Config::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT);\n            }\n\n            // 加载行为扩展文件\n            if (is_file(CONF_PATH . $module . 'tags' . EXT)) {\n                Hook::import(include CONF_PATH . $module . 'tags' . EXT);\n            }\n\n            // 加载公共文件\n            if (is_file($path . 'common' . EXT)) {\n                include $path . 'common' . EXT;\n            }\n\n            // 加载当前模块语言包\n            if ($module) {\n                Lang::load($path . 'lang' . DS . Request::instance()->langset() . EXT);\n            }\n        }\n        return Config::get();\n    }\n\n    /**\n     * URL路由检测（根据PATH_INFO)\n     * @access public\n     * @param  \\think\\Request $request\n     * @param  array          $config\n     * @return array\n     * @throws \\think\\Exception\n     */\n    public static function routeCheck($request, array $config)\n    {\n        $path   = $request->path();\n        $depr   = $config['pathinfo_depr'];\n        $result = false;\n        // 路由检测\n        $check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on'];\n        if ($check) {\n            // 开启路由\n            if (is_file(RUNTIME_PATH . 'route.php')) {\n                // 读取路由缓存\n                $rules = include RUNTIME_PATH . 'route.php';\n                if (is_array($rules)) {\n                    Route::rules($rules);\n                }\n            } else {\n                $files = $config['route_config_file'];\n                foreach ($files as $file) {\n                    if (is_file(CONF_PATH . $file . CONF_EXT)) {\n                        // 导入路由配置\n                        $rules = include CONF_PATH . $file . CONF_EXT;\n                        if (is_array($rules)) {\n                            Route::import($rules);\n                        }\n                    }\n                }\n            }\n\n            // 路由检测（根据路由定义返回不同的URL调度）\n            $result = Route::check($request, $path, $depr, $config['url_domain_deploy']);\n            $must   = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must'];\n            if ($must && false === $result) {\n                // 路由无效\n                throw new RouteNotFoundException();\n            }\n        }\n        if (false === $result) {\n            // 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索\n            $result = Route::parseUrl($path, $depr, $config['controller_auto_search']);\n        }\n        return $result;\n    }\n\n    /**\n     * 设置应用的路由检测机制\n     * @access public\n     * @param  bool $route 是否需要检测路由\n     * @param  bool $must  是否强制检测路由\n     * @return void\n     */\n    public static function route($route, $must = false)\n    {\n        self::$routeCheck = $route;\n        self::$routeMust  = $must;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Build.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nclass Build\n{\n    /**\n     * 根据传入的build资料创建目录和文件\n     * @access protected\n     * @param  array  $build build列表\n     * @param  string $namespace 应用类库命名空间\n     * @param  bool   $suffix 类库后缀\n     * @return void\n     */\n    public static function run(array $build = [], $namespace = 'app', $suffix = false)\n    {\n        // 锁定\n        $lockfile = APP_PATH . 'build.lock';\n        if (is_writable($lockfile)) {\n            return;\n        } elseif (!touch($lockfile)) {\n            throw new Exception('应用目录[' . APP_PATH . ']不可写，目录无法自动生成！<BR>请手动生成项目目录~', 10006);\n        }\n        foreach ($build as $module => $list) {\n            if ('__dir__' == $module) {\n                // 创建目录列表\n                self::buildDir($list);\n            } elseif ('__file__' == $module) {\n                // 创建文件列表\n                self::buildFile($list);\n            } else {\n                // 创建模块\n                self::module($module, $list, $namespace, $suffix);\n            }\n        }\n        // 解除锁定\n        unlink($lockfile);\n    }\n\n    /**\n     * 创建目录\n     * @access protected\n     * @param  array $list 目录列表\n     * @return void\n     */\n    protected static function buildDir($list)\n    {\n        foreach ($list as $dir) {\n            if (!is_dir(APP_PATH . $dir)) {\n                // 创建目录\n                mkdir(APP_PATH . $dir, 0755, true);\n            }\n        }\n    }\n\n    /**\n     * 创建文件\n     * @access protected\n     * @param  array $list 文件列表\n     * @return void\n     */\n    protected static function buildFile($list)\n    {\n        foreach ($list as $file) {\n            if (!is_dir(APP_PATH . dirname($file))) {\n                // 创建目录\n                mkdir(APP_PATH . dirname($file), 0755, true);\n            }\n            if (!is_file(APP_PATH . $file)) {\n                file_put_contents(APP_PATH . $file, 'php' == pathinfo($file, PATHINFO_EXTENSION) ? \"<?php\\n\" : '');\n            }\n        }\n    }\n\n    /**\n     * 创建模块\n     * @access public\n     * @param  string $module 模块名\n     * @param  array  $list build列表\n     * @param  string $namespace 应用类库命名空间\n     * @param  bool   $suffix 类库后缀\n     * @return void\n     */\n    public static function module($module = '', $list = [], $namespace = 'app', $suffix = false)\n    {\n        $module = $module ? $module : '';\n        if (!is_dir(APP_PATH . $module)) {\n            // 创建模块目录\n            mkdir(APP_PATH . $module);\n        }\n        if (basename(RUNTIME_PATH) != $module) {\n            // 创建配置文件和公共文件\n            self::buildCommon($module);\n            // 创建模块的默认页面\n            self::buildHello($module, $namespace, $suffix);\n        }\n        if (empty($list)) {\n            // 创建默认的模块目录和文件\n            $list = [\n                '__file__' => ['config.php', 'common.php'],\n                '__dir__'  => ['controller', 'model', 'view'],\n            ];\n        }\n        // 创建子目录和文件\n        foreach ($list as $path => $file) {\n            $modulePath = APP_PATH . $module . DS;\n            if ('__dir__' == $path) {\n                // 生成子目录\n                foreach ($file as $dir) {\n                    self::checkDirBuild($modulePath . $dir);\n                }\n            } elseif ('__file__' == $path) {\n                // 生成（空白）文件\n                foreach ($file as $name) {\n                    if (!is_file($modulePath . $name)) {\n                        file_put_contents($modulePath . $name, 'php' == pathinfo($name, PATHINFO_EXTENSION) ? \"<?php\\n\" : '');\n                    }\n                }\n            } else {\n                // 生成相关MVC文件\n                foreach ($file as $val) {\n                    $val      = trim($val);\n                    $filename = $modulePath . $path . DS . $val . ($suffix ? ucfirst($path) : '') . EXT;\n                    $space    = $namespace . '\\\\' . ($module ? $module . '\\\\' : '') . $path;\n                    $class    = $val . ($suffix ? ucfirst($path) : '');\n                    switch ($path) {\n                        case 'controller': // 控制器\n                            $content = \"<?php\\nnamespace {$space};\\n\\nclass {$class}\\n{\\n\\n}\";\n                            break;\n                        case 'model': // 模型\n                            $content = \"<?php\\nnamespace {$space};\\n\\nuse think\\Model;\\n\\nclass {$class} extends Model\\n{\\n\\n}\";\n                            break;\n                        case 'view': // 视图\n                            $filename = $modulePath . $path . DS . $val . '.html';\n                            self::checkDirBuild(dirname($filename));\n                            $content = '';\n                            break;\n                        default:\n                            // 其他文件\n                            $content = \"<?php\\nnamespace {$space};\\n\\nclass {$class}\\n{\\n\\n}\";\n                    }\n\n                    if (!is_file($filename)) {\n                        file_put_contents($filename, $content);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 创建模块的欢迎页面\n     * @access public\n     * @param  string $module 模块名\n     * @param  string $namespace 应用类库命名空间\n     * @param  bool   $suffix 类库后缀\n     * @return void\n     */\n    protected static function buildHello($module, $namespace, $suffix = false)\n    {\n        $filename = APP_PATH . ($module ? $module . DS : '') . 'controller' . DS . 'Index' . ($suffix ? 'Controller' : '') . EXT;\n        if (!is_file($filename)) {\n            $content = file_get_contents(THINK_PATH . 'tpl' . DS . 'default_index.tpl');\n            $content = str_replace(['{$app}', '{$module}', '{layer}', '{$suffix}'], [$namespace, $module ? $module . '\\\\' : '', 'controller', $suffix ? 'Controller' : ''], $content);\n            self::checkDirBuild(dirname($filename));\n            file_put_contents($filename, $content);\n        }\n    }\n\n    /**\n     * 创建模块的公共文件\n     * @access public\n     * @param  string $module 模块名\n     * @return void\n     */\n    protected static function buildCommon($module)\n    {\n        $filename = CONF_PATH . ($module ? $module . DS : '') . 'config.php';\n\n        self::checkDirBuild(dirname($filename));\n        if (!is_file($filename)) {\n            file_put_contents($filename, \"<?php\\n//配置文件\\nreturn [\\n\\n];\");\n        }\n        $filename = APP_PATH . ($module ? $module . DS : '') . 'common.php';\n        if (!is_file($filename)) {\n            file_put_contents($filename, \"<?php\\n\");\n        }\n    }\n\n    protected static function checkDirBuild($dirname)\n    {\n        if (!is_dir($dirname)) {\n            mkdir($dirname, 0755, true);\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Cache.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\cache\\Driver;\n\nclass Cache\n{\n    protected static $instance = [];\n    public static $readTimes   = 0;\n    public static $writeTimes  = 0;\n\n    /**\n     * 操作句柄\n     * @var object\n     * @access protected\n     */\n    protected static $handler;\n\n    /**\n     * 连接缓存\n     * @access public\n     * @param array         $options  配置数组\n     * @param bool|string   $name 缓存连接标识 true 强制重新连接\n     * @return Driver\n     */\n    public static function connect(array $options = [], $name = false)\n    {\n        $type = !empty($options['type']) ? $options['type'] : 'File';\n        if (false === $name) {\n            $name = md5(serialize($options));\n        }\n\n        if (true === $name || !isset(self::$instance[$name])) {\n            $class = false !== strpos($type, '\\\\') ? $type : '\\\\think\\\\cache\\\\driver\\\\' . ucwords($type);\n\n            // 记录初始化信息\n            App::$debug && Log::record('[ CACHE ] INIT ' . $type, 'info');\n            if (true === $name) {\n                return new $class($options);\n            } else {\n                self::$instance[$name] = new $class($options);\n            }\n        }\n        return self::$instance[$name];\n    }\n\n    /**\n     * 自动初始化缓存\n     * @access public\n     * @param array         $options  配置数组\n     * @return Driver\n     */\n    public static function init(array $options = [])\n    {\n        if (is_null(self::$handler)) {\n            // 自动初始化缓存\n            if (!empty($options)) {\n                $connect = self::connect($options);\n            } elseif ('complex' == Config::get('cache.type')) {\n                $connect = self::connect(Config::get('cache.default'));\n            } else {\n                $connect = self::connect(Config::get('cache'));\n            }\n            self::$handler = $connect;\n        }\n        return self::$handler;\n    }\n\n    /**\n     * 切换缓存类型 需要配置 cache.type 为 complex\n     * @access public\n     * @param string $name 缓存标识\n     * @return Driver\n     */\n    public static function store($name = '')\n    {\n        if ('' !== $name && 'complex' == Config::get('cache.type')) {\n            return self::connect(Config::get('cache.' . $name), strtolower($name));\n        }\n        return self::init();\n    }\n\n    /**\n     * 判断缓存是否存在\n     * @access public\n     * @param string $name 缓存变量名\n     * @return bool\n     */\n    public static function has($name)\n    {\n        self::$readTimes++;\n        return self::init()->has($name);\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存标识\n     * @param mixed  $default 默认值\n     * @return mixed\n     */\n    public static function get($name, $default = false)\n    {\n        self::$readTimes++;\n        return self::init()->get($name, $default);\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string        $name 缓存标识\n     * @param mixed         $value  存储数据\n     * @param int|null      $expire  有效时间 0为永久\n     * @return boolean\n     */\n    public static function set($name, $value, $expire = null)\n    {\n        self::$writeTimes++;\n        return self::init()->set($name, $value, $expire);\n    }\n\n    /**\n     * 自增缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public static function inc($name, $step = 1)\n    {\n        self::$writeTimes++;\n        return self::init()->inc($name, $step);\n    }\n\n    /**\n     * 自减缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public static function dec($name, $step = 1)\n    {\n        self::$writeTimes++;\n        return self::init()->dec($name, $step);\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string    $name 缓存标识\n     * @return boolean\n     */\n    public static function rm($name)\n    {\n        self::$writeTimes++;\n        return self::init()->rm($name);\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @param string $tag 标签名\n     * @return boolean\n     */\n    public static function clear($tag = null)\n    {\n        self::$writeTimes++;\n        return self::init()->clear($tag);\n    }\n\n    /**\n     * 读取缓存并删除\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public static function pull($name)\n    {\n        self::$readTimes++;\n        self::$writeTimes++;\n        return self::init()->pull($name);\n    }\n\n    /**\n     * 如果不存在则写入缓存\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param mixed     $value  存储数据\n     * @param int       $expire  有效时间 0为永久\n     * @return mixed\n     */\n    public static function remember($name, $value, $expire = null)\n    {\n        self::$readTimes++;\n        return self::init()->remember($name, $value, $expire);\n    }\n\n    /**\n     * 缓存标签\n     * @access public\n     * @param string        $name 标签名\n     * @param string|array  $keys 缓存标识\n     * @param bool          $overlay 是否覆盖\n     * @return Driver\n     */\n    public static function tag($name, $keys = null, $overlay = false)\n    {\n        return self::init()->tag($name, $keys, $overlay);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/Collection.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: zhangyajun <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse ArrayAccess;\nuse ArrayIterator;\nuse Countable;\nuse IteratorAggregate;\nuse JsonSerializable;\n\nclass Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable\n{\n    protected $items = [];\n\n    public function __construct($items = [])\n    {\n        $this->items = $this->convertToArray($items);\n    }\n\n    public static function make($items = [])\n    {\n        return new static($items);\n    }\n\n    /**\n     * 是否为空\n     * @return bool\n     */\n    public function isEmpty()\n    {\n        return empty($this->items);\n    }\n\n    public function toArray()\n    {\n        return array_map(function ($value) {\n            return ($value instanceof Model || $value instanceof self) ? $value->toArray() : $value;\n        }, $this->items);\n    }\n\n    public function all()\n    {\n        return $this->items;\n    }\n\n    /**\n     * 合并数组\n     *\n     * @param  mixed $items\n     * @return static\n     */\n    public function merge($items)\n    {\n        return new static(array_merge($this->items, $this->convertToArray($items)));\n    }\n\n    /**\n     * 比较数组，返回差集\n     *\n     * @param  mixed $items\n     * @return static\n     */\n    public function diff($items)\n    {\n        return new static(array_diff($this->items, $this->convertToArray($items)));\n    }\n\n    /**\n     * 交换数组中的键和值\n     *\n     * @return static\n     */\n    public function flip()\n    {\n        return new static(array_flip($this->items));\n    }\n\n    /**\n     * 比较数组，返回交集\n     *\n     * @param  mixed $items\n     * @return static\n     */\n    public function intersect($items)\n    {\n        return new static(array_intersect($this->items, $this->convertToArray($items)));\n    }\n\n    /**\n     * 返回数组中所有的键名\n     *\n     * @return static\n     */\n    public function keys()\n    {\n        return new static(array_keys($this->items));\n    }\n\n    /**\n     * 删除数组的最后一个元素（出栈）\n     *\n     * @return mixed\n     */\n    public function pop()\n    {\n        return array_pop($this->items);\n    }\n\n    /**\n     * 通过使用用户自定义函数，以字符串返回数组\n     *\n     * @param  callable $callback\n     * @param  mixed    $initial\n     * @return mixed\n     */\n    public function reduce(callable $callback, $initial = null)\n    {\n        return array_reduce($this->items, $callback, $initial);\n    }\n\n    /**\n     * 以相反的顺序返回数组。\n     *\n     * @return static\n     */\n    public function reverse()\n    {\n        return new static(array_reverse($this->items));\n    }\n\n    /**\n     * 删除数组中首个元素，并返回被删除元素的值\n     *\n     * @return mixed\n     */\n    public function shift()\n    {\n        return array_shift($this->items);\n    }\n\n    /**\n     * 把一个数组分割为新的数组块.\n     *\n     * @param  int  $size\n     * @param  bool $preserveKeys\n     * @return static\n     */\n    public function chunk($size, $preserveKeys = false)\n    {\n        $chunks = [];\n\n        foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) {\n            $chunks[] = new static($chunk);\n        }\n\n        return new static($chunks);\n    }\n\n    /**\n     * 在数组开头插入一个元素\n     * @param mixed $value\n     * @param null  $key\n     * @return int\n     */\n    public function unshift($value, $key = null)\n    {\n        if (is_null($key)) {\n            array_unshift($this->items, $value);\n        } else {\n            $this->items = [$key => $value] + $this->items;\n        }\n    }\n\n    /**\n     * 给每个元素执行个回调\n     *\n     * @param  callable $callback\n     * @return $this\n     */\n    public function each(callable $callback)\n    {\n        foreach ($this->items as $key => $item) {\n            if ($callback($item, $key) === false) {\n                break;\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * 用回调函数过滤数组中的元素\n     * @param callable|null $callback\n     * @return static\n     */\n    public function filter(callable $callback = null)\n    {\n        if ($callback) {\n            return new static(array_filter($this->items, $callback));\n        }\n\n        return new static(array_filter($this->items));\n    }\n\n    /**\n     * 返回数组中指定的一列\n     * @param      $column_key\n     * @param null $index_key\n     * @return array\n     */\n    public function column($column_key, $index_key = null)\n    {\n        if (function_exists('array_column')) {\n            return array_column($this->items, $column_key, $index_key);\n        }\n\n        $result = [];\n        foreach ($this->items as $row) {\n            $key    = $value    = null;\n            $keySet = $valueSet = false;\n            if (null !== $index_key && array_key_exists($index_key, $row)) {\n                $keySet = true;\n                $key    = (string) $row[$index_key];\n            }\n            if (null === $column_key) {\n                $valueSet = true;\n                $value    = $row;\n            } elseif (is_array($row) && array_key_exists($column_key, $row)) {\n                $valueSet = true;\n                $value    = $row[$column_key];\n            }\n            if ($valueSet) {\n                if ($keySet) {\n                    $result[$key] = $value;\n                } else {\n                    $result[] = $value;\n                }\n            }\n        }\n        return $result;\n    }\n\n    /**\n     * 对数组排序\n     *\n     * @param  callable|null $callback\n     * @return static\n     */\n    public function sort(callable $callback = null)\n    {\n        $items = $this->items;\n\n        $callback ? uasort($items, $callback) : uasort($items, function ($a, $b) {\n\n            if ($a == $b) {\n                return 0;\n            }\n\n            return ($a < $b) ? -1 : 1;\n        });\n\n        return new static($items);\n    }\n\n    /**\n     * 将数组打乱\n     *\n     * @return static\n     */\n    public function shuffle()\n    {\n        $items = $this->items;\n\n        shuffle($items);\n\n        return new static($items);\n    }\n\n    /**\n     * 截取数组\n     *\n     * @param  int  $offset\n     * @param  int  $length\n     * @param  bool $preserveKeys\n     * @return static\n     */\n    public function slice($offset, $length = null, $preserveKeys = false)\n    {\n        return new static(array_slice($this->items, $offset, $length, $preserveKeys));\n    }\n\n    // ArrayAccess\n    public function offsetExists($offset)\n    {\n        return array_key_exists($offset, $this->items);\n    }\n\n    public function offsetGet($offset)\n    {\n        return $this->items[$offset];\n    }\n\n    public function offsetSet($offset, $value)\n    {\n        if (is_null($offset)) {\n            $this->items[] = $value;\n        } else {\n            $this->items[$offset] = $value;\n        }\n    }\n\n    public function offsetUnset($offset)\n    {\n        unset($this->items[$offset]);\n    }\n\n    //Countable\n    public function count()\n    {\n        return count($this->items);\n    }\n\n    //IteratorAggregate\n    public function getIterator()\n    {\n        return new ArrayIterator($this->items);\n    }\n\n    //JsonSerializable\n    public function jsonSerialize()\n    {\n        return $this->toArray();\n    }\n\n    /**\n     * 转换当前数据集为JSON字符串\n     * @access public\n     * @param integer $options json参数\n     * @return string\n     */\n    public function toJson($options = JSON_UNESCAPED_UNICODE)\n    {\n        return json_encode($this->toArray(), $options);\n    }\n\n    public function __toString()\n    {\n        return $this->toJson();\n    }\n\n    /**\n     * 转换成数组\n     *\n     * @param  mixed $items\n     * @return array\n     */\n    protected function convertToArray($items)\n    {\n        if ($items instanceof self) {\n            return $items->all();\n        }\n        return (array) $items;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Config.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nclass Config\n{\n    // 配置参数\n    private static $config = [];\n    // 参数作用域\n    private static $range = '_sys_';\n\n    // 设定配置参数的作用域\n    public static function range($range)\n    {\n        self::$range = $range;\n        if (!isset(self::$config[$range])) {\n            self::$config[$range] = [];\n        }\n    }\n\n    /**\n     * 解析配置文件或内容\n     * @param string    $config 配置文件路径或内容\n     * @param string    $type 配置解析类型\n     * @param string    $name 配置名（如设置即表示二级配置）\n     * @param string    $range  作用域\n     * @return mixed\n     */\n    public static function parse($config, $type = '', $name = '', $range = '')\n    {\n        $range = $range ?: self::$range;\n        if (empty($type)) {\n            $type = pathinfo($config, PATHINFO_EXTENSION);\n        }\n        $class = false !== strpos($type, '\\\\') ? $type : '\\\\think\\\\config\\\\driver\\\\' . ucwords($type);\n        return self::set((new $class())->parse($config), $name, $range);\n    }\n\n    /**\n     * 加载配置文件（PHP格式）\n     * @param string    $file 配置文件名\n     * @param string    $name 配置名（如设置即表示二级配置）\n     * @param string    $range  作用域\n     * @return mixed\n     */\n    public static function load($file, $name = '', $range = '')\n    {\n        $range = $range ?: self::$range;\n        if (!isset(self::$config[$range])) {\n            self::$config[$range] = [];\n        }\n        if (is_file($file)) {\n            $name = strtolower($name);\n            $type = pathinfo($file, PATHINFO_EXTENSION);\n            if ('php' == $type) {\n                return self::set(include $file, $name, $range);\n            } elseif ('yaml' == $type && function_exists('yaml_parse_file')) {\n                return self::set(yaml_parse_file($file), $name, $range);\n            } else {\n                return self::parse($file, $type, $name, $range);\n            }\n        } else {\n            return self::$config[$range];\n        }\n    }\n\n    /**\n     * 检测配置是否存在\n     * @param string    $name 配置参数名（支持二级配置 .号分割）\n     * @param string    $range  作用域\n     * @return bool\n     */\n    public static function has($name, $range = '')\n    {\n        $range = $range ?: self::$range;\n\n        if (!strpos($name, '.')) {\n            return isset(self::$config[$range][strtolower($name)]);\n        } else {\n            // 二维数组设置和获取支持\n            $name = explode('.', $name, 2);\n            return isset(self::$config[$range][strtolower($name[0])][$name[1]]);\n        }\n    }\n\n    /**\n     * 获取配置参数 为空则获取所有配置\n     * @param string    $name 配置参数名（支持二级配置 .号分割）\n     * @param string    $range  作用域\n     * @return mixed\n     */\n    public static function get($name = null, $range = '')\n    {\n        $range = $range ?: self::$range;\n        // 无参数时获取所有\n        if (empty($name) && isset(self::$config[$range])) {\n            return self::$config[$range];\n        }\n\n        if (!strpos($name, '.')) {\n            $name = strtolower($name);\n            return isset(self::$config[$range][$name]) ? self::$config[$range][$name] : null;\n        } else {\n            // 二维数组设置和获取支持\n            $name    = explode('.', $name, 2);\n            $name[0] = strtolower($name[0]);\n            return isset(self::$config[$range][$name[0]][$name[1]]) ? self::$config[$range][$name[0]][$name[1]] : null;\n        }\n    }\n\n    /**\n     * 设置配置参数 name为数组则为批量设置\n     * @param string|array  $name 配置参数名（支持二级配置 .号分割）\n     * @param mixed         $value 配置值\n     * @param string        $range  作用域\n     * @return mixed\n     */\n    public static function set($name, $value = null, $range = '')\n    {\n        $range = $range ?: self::$range;\n        if (!isset(self::$config[$range])) {\n            self::$config[$range] = [];\n        }\n        if (is_string($name)) {\n            if (!strpos($name, '.')) {\n                self::$config[$range][strtolower($name)] = $value;\n            } else {\n                // 二维数组设置和获取支持\n                $name                                                 = explode('.', $name, 2);\n                self::$config[$range][strtolower($name[0])][$name[1]] = $value;\n            }\n            return;\n        } elseif (is_array($name)) {\n            // 批量设置\n            if (!empty($value)) {\n                self::$config[$range][$value] = isset(self::$config[$range][$value]) ?\n                array_merge(self::$config[$range][$value], $name) :\n                self::$config[$range][$value] = $name;\n                return self::$config[$range][$value];\n            } else {\n                return self::$config[$range] = array_merge(self::$config[$range], array_change_key_case($name));\n            }\n        } else {\n            // 为空直接返回 已有配置\n            return self::$config[$range];\n        }\n    }\n\n    /**\n     * 重置配置参数\n     */\n    public static function reset($range = '')\n    {\n        $range = $range ?: self::$range;\n        if (true === $range) {\n            self::$config = [];\n        } else {\n            self::$config[$range] = [];\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Console.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | TopThink [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2015 http://www.topthink.com All rights reserved.\n// +----------------------------------------------------------------------\n// | Author: zhangyajun <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\console\\Command;\nuse think\\console\\command\\Help as HelpCommand;\nuse think\\console\\Input;\nuse think\\console\\input\\Argument as InputArgument;\nuse think\\console\\input\\Definition as InputDefinition;\nuse think\\console\\input\\Option as InputOption;\nuse think\\console\\Output;\nuse think\\console\\output\\driver\\Buffer;\n\nclass Console\n{\n\n    private $name;\n    private $version;\n\n    /** @var Command[] */\n    private $commands = [];\n\n    private $wantHelps = false;\n\n    private $catchExceptions = true;\n    private $autoExit        = true;\n    private $definition;\n    private $defaultCommand;\n\n    private static $defaultCommands = [\n        \"think\\\\console\\\\command\\\\Help\",\n        \"think\\\\console\\\\command\\\\Lists\",\n        \"think\\\\console\\\\command\\\\Build\",\n        \"think\\\\console\\\\command\\\\Clear\",\n        \"think\\\\console\\\\command\\\\make\\\\Controller\",\n        \"think\\\\console\\\\command\\\\make\\\\Model\",\n        \"think\\\\console\\\\command\\\\optimize\\\\Autoload\",\n        \"think\\\\console\\\\command\\\\optimize\\\\Config\",\n        \"think\\\\console\\\\command\\\\optimize\\\\Route\",\n        \"think\\\\console\\\\command\\\\optimize\\\\Schema\",\n    ];\n\n    public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')\n    {\n        $this->name    = $name;\n        $this->version = $version;\n\n        $this->defaultCommand = 'list';\n        $this->definition     = $this->getDefaultInputDefinition();\n\n        foreach ($this->getDefaultCommands() as $command) {\n            $this->add($command);\n        }\n    }\n\n    public static function init($run = true)\n    {\n        static $console;\n        if (!$console) {\n            // 实例化console\n            $console = new self('Think Console', '0.1');\n            // 读取指令集\n            if (is_file(CONF_PATH . 'command' . EXT)) {\n                $commands = include CONF_PATH . 'command' . EXT;\n                if (is_array($commands)) {\n                    foreach ($commands as $command) {\n                        if (class_exists($command) && is_subclass_of($command, \"\\\\think\\\\console\\\\Command\")) {\n                            // 注册指令\n                            $console->add(new $command());\n                        }\n                    }\n                }\n            }\n        }\n        if ($run) {\n            // 运行\n            return $console->run();\n        } else {\n            return $console;\n        }\n    }\n\n    /**\n     * @param        $command\n     * @param array  $parameters\n     * @param string $driver\n     * @return Output|Buffer\n     */\n    public static function call($command, array $parameters = [], $driver = 'buffer')\n    {\n        $console = self::init(false);\n\n        array_unshift($parameters, $command);\n\n        $input  = new Input($parameters);\n        $output = new Output($driver);\n\n        $console->setCatchExceptions(false);\n        $console->find($command)->run($input, $output);\n\n        return $output;\n    }\n\n    /**\n     * 执行当前的指令\n     * @return int\n     * @throws \\Exception\n     * @api\n     */\n    public function run()\n    {\n        $input  = new Input();\n        $output = new Output();\n\n        $this->configureIO($input, $output);\n\n        try {\n            $exitCode = $this->doRun($input, $output);\n        } catch (\\Exception $e) {\n            if (!$this->catchExceptions) {\n                throw $e;\n            }\n\n            $output->renderException($e);\n\n            $exitCode = $e->getCode();\n            if (is_numeric($exitCode)) {\n                $exitCode = (int) $exitCode;\n                if (0 === $exitCode) {\n                    $exitCode = 1;\n                }\n            } else {\n                $exitCode = 1;\n            }\n        }\n\n        if ($this->autoExit) {\n            if ($exitCode > 255) {\n                $exitCode = 255;\n            }\n\n            exit($exitCode);\n        }\n\n        return $exitCode;\n    }\n\n    /**\n     * 执行指令\n     * @param Input  $input\n     * @param Output $output\n     * @return int\n     */\n    public function doRun(Input $input, Output $output)\n    {\n        if (true === $input->hasParameterOption(['--version', '-V'])) {\n            $output->writeln($this->getLongVersion());\n\n            return 0;\n        }\n\n        $name = $this->getCommandName($input);\n\n        if (true === $input->hasParameterOption(['--help', '-h'])) {\n            if (!$name) {\n                $name  = 'help';\n                $input = new Input(['help']);\n            } else {\n                $this->wantHelps = true;\n            }\n        }\n\n        if (!$name) {\n            $name  = $this->defaultCommand;\n            $input = new Input([$this->defaultCommand]);\n        }\n\n        $command = $this->find($name);\n\n        $exitCode = $this->doRunCommand($command, $input, $output);\n\n        return $exitCode;\n    }\n\n    /**\n     * 设置输入参数定义\n     * @param InputDefinition $definition\n     */\n    public function setDefinition(InputDefinition $definition)\n    {\n        $this->definition = $definition;\n    }\n\n    /**\n     * 获取输入参数定义\n     * @return InputDefinition The InputDefinition instance\n     */\n    public function getDefinition()\n    {\n        return $this->definition;\n    }\n\n    /**\n     * Gets the help message.\n     * @return string A help message.\n     */\n    public function getHelp()\n    {\n        return $this->getLongVersion();\n    }\n\n    /**\n     * 是否捕获异常\n     * @param bool $boolean\n     * @api\n     */\n    public function setCatchExceptions($boolean)\n    {\n        $this->catchExceptions = (bool) $boolean;\n    }\n\n    /**\n     * 是否自动退出\n     * @param bool $boolean\n     * @api\n     */\n    public function setAutoExit($boolean)\n    {\n        $this->autoExit = (bool) $boolean;\n    }\n\n    /**\n     * 获取名称\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * 设置名称\n     * @param string $name\n     */\n    public function setName($name)\n    {\n        $this->name = $name;\n    }\n\n    /**\n     * 获取版本\n     * @return string\n     * @api\n     */\n    public function getVersion()\n    {\n        return $this->version;\n    }\n\n    /**\n     * 设置版本\n     * @param string $version\n     */\n    public function setVersion($version)\n    {\n        $this->version = $version;\n    }\n\n    /**\n     * 获取完整的版本号\n     * @return string\n     */\n    public function getLongVersion()\n    {\n        if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {\n            return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());\n        }\n\n        return '<info>Console Tool</info>';\n    }\n\n    /**\n     * 注册一个指令\n     * @param string $name\n     * @return Command\n     */\n    public function register($name)\n    {\n        return $this->add(new Command($name));\n    }\n\n    /**\n     * 添加指令\n     * @param Command[] $commands\n     */\n    public function addCommands(array $commands)\n    {\n        foreach ($commands as $command) {\n            $this->add($command);\n        }\n    }\n\n    /**\n     * 添加一个指令\n     * @param Command $command\n     * @return Command\n     */\n    public function add(Command $command)\n    {\n        $command->setConsole($this);\n\n        if (!$command->isEnabled()) {\n            $command->setConsole(null);\n            return;\n        }\n\n        if (null === $command->getDefinition()) {\n            throw new \\LogicException(sprintf('Command class \"%s\" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));\n        }\n\n        $this->commands[$command->getName()] = $command;\n\n        foreach ($command->getAliases() as $alias) {\n            $this->commands[$alias] = $command;\n        }\n\n        return $command;\n    }\n\n    /**\n     * 获取指令\n     * @param string $name 指令名称\n     * @return Command\n     * @throws \\InvalidArgumentException\n     */\n    public function get($name)\n    {\n        if (!isset($this->commands[$name])) {\n            throw new \\InvalidArgumentException(sprintf('The command \"%s\" does not exist.', $name));\n        }\n\n        $command = $this->commands[$name];\n\n        if ($this->wantHelps) {\n            $this->wantHelps = false;\n\n            /** @var HelpCommand $helpCommand */\n            $helpCommand = $this->get('help');\n            $helpCommand->setCommand($command);\n\n            return $helpCommand;\n        }\n\n        return $command;\n    }\n\n    /**\n     * 某个指令是否存在\n     * @param string $name 指令名称\n     * @return bool\n     */\n    public function has($name)\n    {\n        return isset($this->commands[$name]);\n    }\n\n    /**\n     * 获取所有的命名空间\n     * @return array\n     */\n    public function getNamespaces()\n    {\n        $namespaces = [];\n        foreach ($this->commands as $command) {\n            $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));\n\n            foreach ($command->getAliases() as $alias) {\n                $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));\n            }\n        }\n\n        return array_values(array_unique(array_filter($namespaces)));\n    }\n\n    /**\n     * 查找注册命名空间中的名称或缩写。\n     * @param string $namespace\n     * @return string\n     * @throws \\InvalidArgumentException\n     */\n    public function findNamespace($namespace)\n    {\n        $allNamespaces = $this->getNamespaces();\n        $expr          = preg_replace_callback('{([^:]+|)}', function ($matches) {\n            return preg_quote($matches[1]) . '[^:]*';\n        }, $namespace);\n        $namespaces = preg_grep('{^' . $expr . '}', $allNamespaces);\n\n        if (empty($namespaces)) {\n            $message = sprintf('There are no commands defined in the \"%s\" namespace.', $namespace);\n\n            if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {\n                if (1 == count($alternatives)) {\n                    $message .= \"\\n\\nDid you mean this?\\n    \";\n                } else {\n                    $message .= \"\\n\\nDid you mean one of these?\\n    \";\n                }\n\n                $message .= implode(\"\\n    \", $alternatives);\n            }\n\n            throw new \\InvalidArgumentException($message);\n        }\n\n        $exact = in_array($namespace, $namespaces, true);\n        if (count($namespaces) > 1 && !$exact) {\n            throw new \\InvalidArgumentException(sprintf('The namespace \"%s\" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))));\n        }\n\n        return $exact ? $namespace : reset($namespaces);\n    }\n\n    /**\n     * 查找指令\n     * @param string $name 名称或者别名\n     * @return Command\n     * @throws \\InvalidArgumentException\n     */\n    public function find($name)\n    {\n        $allCommands = array_keys($this->commands);\n        $expr        = preg_replace_callback('{([^:]+|)}', function ($matches) {\n            return preg_quote($matches[1]) . '[^:]*';\n        }, $name);\n        $commands = preg_grep('{^' . $expr . '}', $allCommands);\n\n        if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) {\n            if (false !== $pos = strrpos($name, ':')) {\n                $this->findNamespace(substr($name, 0, $pos));\n            }\n\n            $message = sprintf('Command \"%s\" is not defined.', $name);\n\n            if ($alternatives = $this->findAlternatives($name, $allCommands)) {\n                if (1 == count($alternatives)) {\n                    $message .= \"\\n\\nDid you mean this?\\n    \";\n                } else {\n                    $message .= \"\\n\\nDid you mean one of these?\\n    \";\n                }\n                $message .= implode(\"\\n    \", $alternatives);\n            }\n\n            throw new \\InvalidArgumentException($message);\n        }\n\n        if (count($commands) > 1) {\n            $commandList = $this->commands;\n            $commands    = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {\n                $commandName = $commandList[$nameOrAlias]->getName();\n\n                return $commandName === $nameOrAlias || !in_array($commandName, $commands);\n            });\n        }\n\n        $exact = in_array($name, $commands, true);\n        if (count($commands) > 1 && !$exact) {\n            $suggestions = $this->getAbbreviationSuggestions(array_values($commands));\n\n            throw new \\InvalidArgumentException(sprintf('Command \"%s\" is ambiguous (%s).', $name, $suggestions));\n        }\n\n        return $this->get($exact ? $name : reset($commands));\n    }\n\n    /**\n     * 获取所有的指令\n     * @param string $namespace 命名空间\n     * @return Command[]\n     * @api\n     */\n    public function all($namespace = null)\n    {\n        if (null === $namespace) {\n            return $this->commands;\n        }\n\n        $commands = [];\n        foreach ($this->commands as $name => $command) {\n            if ($this->extractNamespace($name, substr_count($namespace, ':') + 1) === $namespace) {\n                $commands[$name] = $command;\n            }\n        }\n\n        return $commands;\n    }\n\n    /**\n     * 获取可能的指令名\n     * @param array $names\n     * @return array\n     */\n    public static function getAbbreviations($names)\n    {\n        $abbrevs = [];\n        foreach ($names as $name) {\n            for ($len = strlen($name); $len > 0; --$len) {\n                $abbrev             = substr($name, 0, $len);\n                $abbrevs[$abbrev][] = $name;\n            }\n        }\n\n        return $abbrevs;\n    }\n\n    /**\n     * 配置基于用户的参数和选项的输入和输出实例。\n     * @param Input  $input  输入实例\n     * @param Output $output 输出实例\n     */\n    protected function configureIO(Input $input, Output $output)\n    {\n        if (true === $input->hasParameterOption(['--ansi'])) {\n            $output->setDecorated(true);\n        } elseif (true === $input->hasParameterOption(['--no-ansi'])) {\n            $output->setDecorated(false);\n        }\n\n        if (true === $input->hasParameterOption(['--no-interaction', '-n'])) {\n            $input->setInteractive(false);\n        }\n\n        if (true === $input->hasParameterOption(['--quiet', '-q'])) {\n            $output->setVerbosity(Output::VERBOSITY_QUIET);\n        } else {\n            if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) {\n                $output->setVerbosity(Output::VERBOSITY_DEBUG);\n            } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) {\n                $output->setVerbosity(Output::VERBOSITY_VERY_VERBOSE);\n            } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {\n                $output->setVerbosity(Output::VERBOSITY_VERBOSE);\n            }\n        }\n    }\n\n    /**\n     * 执行指令\n     * @param Command $command 指令实例\n     * @param Input   $input   输入实例\n     * @param Output  $output  输出实例\n     * @return int\n     * @throws \\Exception\n     */\n    protected function doRunCommand(Command $command, Input $input, Output $output)\n    {\n        return $command->run($input, $output);\n    }\n\n    /**\n     * 获取指令的基础名称\n     * @param Input $input\n     * @return string\n     */\n    protected function getCommandName(Input $input)\n    {\n        return $input->getFirstArgument();\n    }\n\n    /**\n     * 获取默认输入定义\n     * @return InputDefinition\n     */\n    protected function getDefaultInputDefinition()\n    {\n        return new InputDefinition([\n            new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),\n            new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),\n            new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this console version'),\n            new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),\n            new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),\n            new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),\n            new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),\n            new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),\n        ]);\n    }\n\n    /**\n     * 设置默认命令\n     * @return Command[] An array of default Command instances\n     */\n    protected function getDefaultCommands()\n    {\n        $defaultCommands = [];\n\n        foreach (self::$defaultCommands as $classname) {\n            if (class_exists($classname) && is_subclass_of($classname, \"think\\\\console\\\\Command\")) {\n                $defaultCommands[] = new $classname();\n            }\n        }\n\n        return $defaultCommands;\n    }\n\n    public static function addDefaultCommands(array $classnames)\n    {\n        self::$defaultCommands = array_merge(self::$defaultCommands, $classnames);\n    }\n\n    /**\n     * 获取可能的建议\n     * @param array $abbrevs\n     * @return string\n     */\n    private function getAbbreviationSuggestions($abbrevs)\n    {\n        return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');\n    }\n\n    /**\n     * 返回命名空间部分\n     * @param string $name  指令\n     * @param string $limit 部分的命名空间的最大数量\n     * @return string\n     */\n    public function extractNamespace($name, $limit = null)\n    {\n        $parts = explode(':', $name);\n        array_pop($parts);\n\n        return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit));\n    }\n\n    /**\n     * 查找可替代的建议\n     * @param string             $name\n     * @param array|\\Traversable $collection\n     * @return array\n     */\n    private function findAlternatives($name, $collection)\n    {\n        $threshold    = 1e3;\n        $alternatives = [];\n\n        $collectionParts = [];\n        foreach ($collection as $item) {\n            $collectionParts[$item] = explode(':', $item);\n        }\n\n        foreach (explode(':', $name) as $i => $subname) {\n            foreach ($collectionParts as $collectionName => $parts) {\n                $exists = isset($alternatives[$collectionName]);\n                if (!isset($parts[$i]) && $exists) {\n                    $alternatives[$collectionName] += $threshold;\n                    continue;\n                } elseif (!isset($parts[$i])) {\n                    continue;\n                }\n\n                $lev = levenshtein($subname, $parts[$i]);\n                if ($lev <= strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {\n                    $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;\n                } elseif ($exists) {\n                    $alternatives[$collectionName] += $threshold;\n                }\n            }\n        }\n\n        foreach ($collection as $item) {\n            $lev = levenshtein($name, $item);\n            if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {\n                $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;\n            }\n        }\n\n        $alternatives = array_filter($alternatives, function ($lev) use ($threshold) {\n            return $lev < 2 * $threshold;\n        });\n        asort($alternatives);\n\n        return array_keys($alternatives);\n    }\n\n    /**\n     * 设置默认的指令\n     * @param string $commandName The Command name\n     */\n    public function setDefaultCommand($commandName)\n    {\n        $this->defaultCommand = $commandName;\n    }\n\n    /**\n     * 返回所有的命名空间\n     * @param string $name\n     * @return array\n     */\n    private function extractAllNamespaces($name)\n    {\n        $parts      = explode(':', $name, -1);\n        $namespaces = [];\n\n        foreach ($parts as $part) {\n            if (count($namespaces)) {\n                $namespaces[] = end($namespaces) . ':' . $part;\n            } else {\n                $namespaces[] = $part;\n            }\n        }\n\n        return $namespaces;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/Controller.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\n\\think\\Loader::import('controller/Jump', TRAIT_PATH, EXT);\n\nuse think\\exception\\ValidateException;\n\nclass Controller\n{\n    use \\traits\\controller\\Jump;\n\n    /**\n     * @var \\think\\View 视图类实例\n     */\n    protected $view;\n    /**\n     * @var \\think\\Request Request实例\n     */\n    protected $request;\n    // 验证失败是否抛出异常\n    protected $failException = false;\n    // 是否批量验证\n    protected $batchValidate = false;\n\n    /**\n     * 前置操作方法列表\n     * @var array $beforeActionList\n     * @access protected\n     */\n    protected $beforeActionList = [];\n\n    /**\n     * 构造方法\n     * @param Request $request Request对象\n     * @access public\n     */\n    public function __construct(Request $request = null)\n    {\n        if (is_null($request)) {\n            $request = Request::instance();\n        }\n        $this->view    = View::instance(Config::get('template'), Config::get('view_replace_str'));\n        $this->request = $request;\n\n        // 控制器初始化\n        $this->_initialize();\n\n        // 前置操作方法\n        if ($this->beforeActionList) {\n            foreach ($this->beforeActionList as $method => $options) {\n                is_numeric($method) ?\n                $this->beforeAction($options) :\n                $this->beforeAction($method, $options);\n            }\n        }\n    }\n\n    // 初始化\n    protected function _initialize()\n    {\n    }\n\n    /**\n     * 前置操作\n     * @access protected\n     * @param string $method  前置操作方法名\n     * @param array  $options 调用参数 ['only'=>[...]] 或者['except'=>[...]]\n     */\n    protected function beforeAction($method, $options = [])\n    {\n        if (isset($options['only'])) {\n            if (is_string($options['only'])) {\n                $options['only'] = explode(',', $options['only']);\n            }\n            if (!in_array($this->request->action(), $options['only'])) {\n                return;\n            }\n        } elseif (isset($options['except'])) {\n            if (is_string($options['except'])) {\n                $options['except'] = explode(',', $options['except']);\n            }\n            if (in_array($this->request->action(), $options['except'])) {\n                return;\n            }\n        }\n\n        call_user_func([$this, $method]);\n    }\n\n    /**\n     * 加载模板输出\n     * @access protected\n     * @param string $template 模板文件名\n     * @param array  $vars     模板输出变量\n     * @param array  $replace  模板替换\n     * @param array  $config   模板参数\n     * @return mixed\n     */\n    protected function fetch($template = '', $vars = [], $replace = [], $config = [])\n    {\n        return $this->view->fetch($template, $vars, $replace, $config);\n    }\n\n    /**\n     * 渲染内容输出\n     * @access protected\n     * @param string $content 模板内容\n     * @param array  $vars    模板输出变量\n     * @param array  $replace 替换内容\n     * @param array  $config  模板参数\n     * @return mixed\n     */\n    protected function display($content = '', $vars = [], $replace = [], $config = [])\n    {\n        return $this->view->display($content, $vars, $replace, $config);\n    }\n\n    /**\n     * 模板变量赋值\n     * @access protected\n     * @param mixed $name  要显示的模板变量\n     * @param mixed $value 变量的值\n     * @return void\n     */\n    protected function assign($name, $value = '')\n    {\n        $this->view->assign($name, $value);\n    }\n\n    /**\n     * 初始化模板引擎\n     * @access protected\n     * @param array|string $engine 引擎参数\n     * @return void\n     */\n    protected function engine($engine)\n    {\n        $this->view->engine($engine);\n    }\n\n    /**\n     * 设置验证失败后是否抛出异常\n     * @access protected\n     * @param bool $fail 是否抛出异常\n     * @return $this\n     */\n    protected function validateFailException($fail = true)\n    {\n        $this->failException = $fail;\n        return $this;\n    }\n\n    /**\n     * 验证数据\n     * @access protected\n     * @param array        $data     数据\n     * @param string|array $validate 验证器名或者验证规则数组\n     * @param array        $message  提示信息\n     * @param bool         $batch    是否批量验证\n     * @param mixed        $callback 回调方法（闭包）\n     * @return array|string|true\n     * @throws ValidateException\n     */\n    protected function validate($data, $validate, $message = [], $batch = false, $callback = null)\n    {\n        if (is_array($validate)) {\n            $v = Loader::validate();\n            $v->rule($validate);\n        } else {\n            if (strpos($validate, '.')) {\n                // 支持场景\n                list($validate, $scene) = explode('.', $validate);\n            }\n            $v = Loader::validate($validate);\n            if (!empty($scene)) {\n                $v->scene($scene);\n            }\n        }\n        // 是否批量验证\n        if ($batch || $this->batchValidate) {\n            $v->batch(true);\n        }\n\n        if (is_array($message)) {\n            $v->message($message);\n        }\n\n        if ($callback && is_callable($callback)) {\n            call_user_func_array($callback, [$v, &$data]);\n        }\n\n        if (!$v->check($data)) {\n            if ($this->failException) {\n                throw new ValidateException($v->getError());\n            } else {\n                return $v->getError();\n            }\n        } else {\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Cookie.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nclass Cookie\n{\n    protected static $config = [\n        // cookie 名称前缀\n        'prefix'    => '',\n        // cookie 保存时间\n        'expire'    => 0,\n        // cookie 保存路径\n        'path'      => '/',\n        // cookie 有效域名\n        'domain'    => '',\n        //  cookie 启用安全传输\n        'secure'    => false,\n        // httponly设置\n        'httponly'  => '',\n        // 是否使用 setcookie\n        'setcookie' => true,\n    ];\n\n    protected static $init;\n\n    /**\n     * Cookie初始化\n     * @param array $config\n     * @return void\n     */\n    public static function init(array $config = [])\n    {\n        if (empty($config)) {\n            $config = Config::get('cookie');\n        }\n        self::$config = array_merge(self::$config, array_change_key_case($config));\n        if (!empty(self::$config['httponly'])) {\n            ini_set('session.cookie_httponly', 1);\n        }\n        self::$init = true;\n    }\n\n    /**\n     * 设置或者获取cookie作用域（前缀）\n     * @param string $prefix\n     * @return string|void\n     */\n    public static function prefix($prefix = '')\n    {\n        if (empty($prefix)) {\n            return self::$config['prefix'];\n        }\n        self::$config['prefix'] = $prefix;\n    }\n\n    /**\n     * Cookie 设置、获取、删除\n     *\n     * @param string $name  cookie名称\n     * @param mixed  $value cookie值\n     * @param mixed  $option 可选参数 可能会是 null|integer|string\n     *\n     * @return mixed\n     * @internal param mixed $options cookie参数\n     */\n    public static function set($name, $value = '', $option = null)\n    {\n        !isset(self::$init) && self::init();\n        // 参数设置(会覆盖黙认设置)\n        if (!is_null($option)) {\n            if (is_numeric($option)) {\n                $option = ['expire' => $option];\n            } elseif (is_string($option)) {\n                parse_str($option, $option);\n            }\n            $config = array_merge(self::$config, array_change_key_case($option));\n        } else {\n            $config = self::$config;\n        }\n        $name = $config['prefix'] . $name;\n        // 设置cookie\n        if (is_array($value)) {\n            array_walk_recursive($value, 'self::jsonFormatProtect', 'encode');\n            $value = 'think:' . json_encode($value);\n        }\n        $expire = !empty($config['expire']) ? $_SERVER['REQUEST_TIME'] + intval($config['expire']) : 0;\n        if ($config['setcookie']) {\n            setcookie($name, $value, $expire, $config['path'], $config['domain'], $config['secure'], $config['httponly']);\n        }\n        $_COOKIE[$name] = $value;\n    }\n\n    /**\n     * 永久保存Cookie数据\n     * @param string $name  cookie名称\n     * @param mixed  $value cookie值\n     * @param mixed  $option 可选参数 可能会是 null|integer|string\n     * @return void\n     */\n    public static function forever($name, $value = '', $option = null)\n    {\n        if (is_null($option) || is_numeric($option)) {\n            $option = [];\n        }\n        $option['expire'] = 315360000;\n        self::set($name, $value, $option);\n    }\n\n    /**\n     * 判断Cookie数据\n     * @param string        $name cookie名称\n     * @param string|null   $prefix cookie前缀\n     * @return bool\n     */\n    public static function has($name, $prefix = null)\n    {\n        !isset(self::$init) && self::init();\n        $prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];\n        $name   = $prefix . $name;\n        return isset($_COOKIE[$name]);\n    }\n\n    /**\n     * Cookie获取\n     * @param string        $name cookie名称\n     * @param string|null   $prefix cookie前缀\n     * @return mixed\n     */\n    public static function get($name = '', $prefix = null)\n    {\n        !isset(self::$init) && self::init();\n        $prefix = !is_null($prefix) ? $prefix : self::$config['prefix'];\n        $key    = $prefix . $name;\n\n        if ('' == $name) {\n            // 获取全部\n            if ($prefix) {\n                $value = [];\n                foreach ($_COOKIE as $k => $val) {\n                    if (0 === strpos($k, $prefix)) {\n                        $value[$k] = $val;\n                    }\n                }\n            } else {\n                $value = $_COOKIE;\n            }\n        } elseif (isset($_COOKIE[$key])) {\n            $value = $_COOKIE[$key];\n            if (0 === strpos($value, 'think:')) {\n                $value = substr($value, 6);\n                $value = json_decode($value, true);\n                array_walk_recursive($value, 'self::jsonFormatProtect', 'decode');\n            }\n        } else {\n            $value = null;\n        }\n        return $value;\n    }\n\n    /**\n     * Cookie删除\n     * @param string        $name cookie名称\n     * @param string|null   $prefix cookie前缀\n     * @return mixed\n     */\n    public static function delete($name, $prefix = null)\n    {\n        !isset(self::$init) && self::init();\n        $config = self::$config;\n        $prefix = !is_null($prefix) ? $prefix : $config['prefix'];\n        $name   = $prefix . $name;\n        if ($config['setcookie']) {\n            setcookie($name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);\n        }\n        // 删除指定cookie\n        unset($_COOKIE[$name]);\n    }\n\n    /**\n     * Cookie清空\n     * @param string|null $prefix cookie前缀\n     * @return mixed\n     */\n    public static function clear($prefix = null)\n    {\n        // 清除指定前缀的所有cookie\n        if (empty($_COOKIE)) {\n            return;\n        }\n        !isset(self::$init) && self::init();\n        // 要删除的cookie前缀，不指定则删除config设置的指定前缀\n        $config = self::$config;\n        $prefix = !is_null($prefix) ? $prefix : $config['prefix'];\n        if ($prefix) {\n            // 如果前缀为空字符串将不作处理直接返回\n            foreach ($_COOKIE as $key => $val) {\n                if (0 === strpos($key, $prefix)) {\n                    if ($config['setcookie']) {\n                        setcookie($key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);\n                    }\n                    unset($_COOKIE[$key]);\n                }\n            }\n        }\n        return;\n    }\n\n    private static function jsonFormatProtect(&$val, $key, $type = 'encode')\n    {\n        if (!empty($val) && true !== $val) {\n            $val = 'decode' == $type ? urldecode($val) : urlencode($val);\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/Db.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\db\\Connection;\nuse think\\db\\Query;\n\n/**\n * Class Db\n * @package think\n * @method Query table(string $table) static 指定数据表（含前缀）\n * @method Query name(string $name) static 指定数据表（不含前缀）\n * @method Query where(mixed $field, string $op = null, mixed $condition = null) static 查询条件\n * @method Query join(mixed $join, mixed $condition = null, string $type = 'INNER') static JOIN查询\n * @method Query union(mixed $union, boolean $all = false) static UNION查询\n * @method Query limit(mixed $offset, integer $length = null) static 查询LIMIT\n * @method Query order(mixed $field, string $order = null) static 查询ORDER\n * @method Query cache(mixed $key = null , integer $expire = null) static 设置查询缓存\n * @method mixed value(string $field) static 获取某个字段的值\n * @method array column(string $field, string $key = '') static 获取某个列的值\n * @method Query view(mixed $join, mixed $field = null, mixed $on = null, string $type = 'INNER') static 视图查询\n * @method mixed find(mixed $data = null) static 查询单个记录\n * @method mixed select(mixed $data = null) static 查询多个记录\n * @method integer insert(array $data, boolean $replace = false, boolean $getLastInsID = false, string $sequence = null) static 插入一条记录\n * @method integer insertGetId(array $data, boolean $replace = false, string $sequence = null) static 插入一条记录并返回自增ID\n * @method integer insertAll(array $dataSet) static 插入多条记录\n * @method integer update(array $data) static 更新记录\n * @method integer delete(mixed $data = null) static 删除记录\n * @method boolean chunk(integer $count, callable $callback, string $column = null) static 分块获取数据\n * @method mixed query(string $sql, array $bind = [], boolean $master = false, bool $pdo = false) static SQL查询\n * @method integer execute(string $sql, array $bind = [], boolean $fetch = false, boolean $getLastInsID = false, string $sequence = null) static SQL执行\n * @method Paginator paginate(integer $listRows = 15, mixed $simple = null, array $config = []) static 分页查询\n * @method mixed transaction(callable $callback) static 执行数据库事务\n * @method void startTrans() static 启动事务\n * @method void commit() static 用于非自动提交状态下面的查询提交\n * @method void rollback() static 事务回滚\n * @method boolean batchQuery(array $sqlArray) static 批处理执行SQL语句\n * @method string quote(string $str) static SQL指令安全过滤\n * @method string getLastInsID($sequence = null) static 获取最近插入的ID\n */\nclass Db\n{\n    //  数据库连接实例\n    private static $instance = [];\n    // 查询次数\n    public static $queryTimes = 0;\n    // 执行次数\n    public static $executeTimes = 0;\n\n    /**\n     * 数据库初始化 并取得数据库类实例\n     * @static\n     * @access public\n     * @param mixed         $config 连接配置\n     * @param bool|string   $name 连接标识 true 强制重新连接\n     * @return Connection\n     * @throws Exception\n     */\n    public static function connect($config = [], $name = false)\n    {\n        if (false === $name) {\n            $name = md5(serialize($config));\n        }\n        if (true === $name || !isset(self::$instance[$name])) {\n            // 解析连接参数 支持数组和字符串\n            $options = self::parseConfig($config);\n            if (empty($options['type'])) {\n                throw new \\InvalidArgumentException('Undefined db type');\n            }\n            $class = false !== strpos($options['type'], '\\\\') ? $options['type'] : '\\\\think\\\\db\\\\connector\\\\' . ucwords($options['type']);\n            // 记录初始化信息\n            if (App::$debug) {\n                Log::record('[ DB ] INIT ' . $options['type'], 'info');\n            }\n            if (true === $name) {\n                return new $class($options);\n            } else {\n                self::$instance[$name] = new $class($options);\n            }\n        }\n        return self::$instance[$name];\n    }\n\n    /**\n     * 数据库连接参数解析\n     * @static\n     * @access private\n     * @param mixed $config\n     * @return array\n     */\n    private static function parseConfig($config)\n    {\n        if (empty($config)) {\n            $config = Config::get('database');\n        } elseif (is_string($config) && false === strpos($config, '/')) {\n            // 支持读取配置参数\n            $config = Config::get($config);\n        }\n        if (is_string($config)) {\n            return self::parseDsn($config);\n        } else {\n            return $config;\n        }\n    }\n\n    /**\n     * DSN解析\n     * 格式： mysql://username:passwd@localhost:3306/DbName?param1=val1&param2=val2#utf8\n     * @static\n     * @access private\n     * @param string $dsnStr\n     * @return array\n     */\n    private static function parseDsn($dsnStr)\n    {\n        $info = parse_url($dsnStr);\n        if (!$info) {\n            return [];\n        }\n        $dsn = [\n            'type'     => $info['scheme'],\n            'username' => isset($info['user']) ? $info['user'] : '',\n            'password' => isset($info['pass']) ? $info['pass'] : '',\n            'hostname' => isset($info['host']) ? $info['host'] : '',\n            'hostport' => isset($info['port']) ? $info['port'] : '',\n            'database' => !empty($info['path']) ? ltrim($info['path'], '/') : '',\n            'charset'  => isset($info['fragment']) ? $info['fragment'] : 'utf8',\n        ];\n\n        if (isset($info['query'])) {\n            parse_str($info['query'], $dsn['params']);\n        } else {\n            $dsn['params'] = [];\n        }\n        return $dsn;\n    }\n\n    // 调用驱动类的方法\n    public static function __callStatic($method, $params)\n    {\n        // 自动初始化数据库\n        return call_user_func_array([self::connect(), $method], $params);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Debug.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\exception\\ClassNotFoundException;\nuse think\\response\\Redirect;\n\nclass Debug\n{\n    // 区间时间信息\n    protected static $info = [];\n    // 区间内存信息\n    protected static $mem = [];\n\n    /**\n     * 记录时间（微秒）和内存使用情况\n     * @param string    $name 标记位置\n     * @param mixed     $value 标记值 留空则取当前 time 表示仅记录时间 否则同时记录时间和内存\n     * @return mixed\n     */\n    public static function remark($name, $value = '')\n    {\n        // 记录时间和内存使用\n        self::$info[$name] = is_float($value) ? $value : microtime(true);\n        if ('time' != $value) {\n            self::$mem['mem'][$name]  = is_float($value) ? $value : memory_get_usage();\n            self::$mem['peak'][$name] = memory_get_peak_usage();\n        }\n    }\n\n    /**\n     * 统计某个区间的时间（微秒）使用情况 返回值以秒为单位\n     * @param string            $start 开始标签\n     * @param string            $end 结束标签\n     * @param integer|string    $dec 小数位\n     * @return integer\n     */\n    public static function getRangeTime($start, $end, $dec = 6)\n    {\n        if (!isset(self::$info[$end])) {\n            self::$info[$end] = microtime(true);\n        }\n        return number_format((self::$info[$end] - self::$info[$start]), $dec);\n    }\n\n    /**\n     * 统计从开始到统计时的时间（微秒）使用情况 返回值以秒为单位\n     * @param integer|string $dec 小数位\n     * @return integer\n     */\n    public static function getUseTime($dec = 6)\n    {\n        return number_format((microtime(true) - THINK_START_TIME), $dec);\n    }\n\n    /**\n     * 获取当前访问的吞吐率情况\n     * @return string\n     */\n    public static function getThroughputRate()\n    {\n        return number_format(1 / self::getUseTime(), 2) . 'req/s';\n    }\n\n    /**\n     * 记录区间的内存使用情况\n     * @param string            $start 开始标签\n     * @param string            $end 结束标签\n     * @param integer|string    $dec 小数位\n     * @return string\n     */\n    public static function getRangeMem($start, $end, $dec = 2)\n    {\n        if (!isset(self::$mem['mem'][$end])) {\n            self::$mem['mem'][$end] = memory_get_usage();\n        }\n        $size = self::$mem['mem'][$end] - self::$mem['mem'][$start];\n        $a    = ['B', 'KB', 'MB', 'GB', 'TB'];\n        $pos  = 0;\n        while ($size >= 1024) {\n            $size /= 1024;\n            $pos++;\n        }\n        return round($size, $dec) . \" \" . $a[$pos];\n    }\n\n    /**\n     * 统计从开始到统计时的内存使用情况\n     * @param integer|string $dec 小数位\n     * @return string\n     */\n    public static function getUseMem($dec = 2)\n    {\n        $size = memory_get_usage() - THINK_START_MEM;\n        $a    = ['B', 'KB', 'MB', 'GB', 'TB'];\n        $pos  = 0;\n        while ($size >= 1024) {\n            $size /= 1024;\n            $pos++;\n        }\n        return round($size, $dec) . \" \" . $a[$pos];\n    }\n\n    /**\n     * 统计区间的内存峰值情况\n     * @param string            $start 开始标签\n     * @param string            $end 结束标签\n     * @param integer|string    $dec 小数位\n     * @return mixed\n     */\n    public static function getMemPeak($start, $end, $dec = 2)\n    {\n        if (!isset(self::$mem['peak'][$end])) {\n            self::$mem['peak'][$end] = memory_get_peak_usage();\n        }\n        $size = self::$mem['peak'][$end] - self::$mem['peak'][$start];\n        $a    = ['B', 'KB', 'MB', 'GB', 'TB'];\n        $pos  = 0;\n        while ($size >= 1024) {\n            $size /= 1024;\n            $pos++;\n        }\n        return round($size, $dec) . \" \" . $a[$pos];\n    }\n\n    /**\n     * 获取文件加载信息\n     * @param bool  $detail 是否显示详细\n     * @return integer|array\n     */\n    public static function getFile($detail = false)\n    {\n        if ($detail) {\n            $files = get_included_files();\n            $info  = [];\n            foreach ($files as $key => $file) {\n                $info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )';\n            }\n            return $info;\n        }\n        return count(get_included_files());\n    }\n\n    /**\n     * 浏览器友好的变量输出\n     * @param mixed         $var 变量\n     * @param boolean       $echo 是否输出 默认为true 如果为false 则返回输出字符串\n     * @param string        $label 标签 默认为空\n     * @param integer       $flags htmlspecialchars flags\n     * @return void|string\n     */\n    public static function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE)\n    {\n        $label = (null === $label) ? '' : rtrim($label) . ':';\n        ob_start();\n        var_dump($var);\n        $output = ob_get_clean();\n        $output = preg_replace('/\\]\\=\\>\\n(\\s+)/m', '] => ', $output);\n        if (IS_CLI) {\n            $output = PHP_EOL . $label . $output . PHP_EOL;\n        } else {\n            if (!extension_loaded('xdebug')) {\n                $output = htmlspecialchars($output, $flags);\n            }\n            $output = '<pre>' . $label . $output . '</pre>';\n        }\n        if ($echo) {\n            echo($output);\n            return;\n        } else {\n            return $output;\n        }\n    }\n\n    public static function inject(Response $response, &$content)\n    {\n        $config  = Config::get('trace');\n        $type    = isset($config['type']) ? $config['type'] : 'Html';\n        $request = Request::instance();\n        $class   = false !== strpos($type, '\\\\') ? $type : '\\\\think\\\\debug\\\\' . ucwords($type);\n        unset($config['type']);\n        if (class_exists($class)) {\n            $trace = new $class($config);\n        } else {\n            throw new ClassNotFoundException('class not exists:' . $class, $class);\n        }\n\n        if ($response instanceof Redirect) {\n            //TODO 记录\n        } else {\n            $output = $trace->output($response, Log::getLog());\n            if (is_string($output)) {\n                // trace调试信息注入\n                $pos = strripos($content, '</body>');\n                if (false !== $pos) {\n                    $content = substr($content, 0, $pos) . $output . substr($content, $pos);\n                } else {\n                    $content = $content . $output;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Env.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nclass Env\n{\n    /**\n     * 获取环境变量值\n     * @param string    $name 环境变量名（支持二级 .号分割）\n     * @param string    $default  默认值\n     * @return mixed\n     */\n    public static function get($name, $default = null)\n    {\n        $result = getenv(ENV_PREFIX . strtoupper(str_replace('.', '_', $name)));\n        if (false !== $result) {\n            if ('false' === $result) {\n                $result = false;\n            } elseif ('true' === $result) {\n                $result = true;\n            }\n            return $result;\n        } else {\n            return $default;\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Error.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\console\\Output as ConsoleOutput;\nuse think\\exception\\ErrorException;\nuse think\\exception\\Handle;\nuse think\\exception\\ThrowableError;\n\nclass Error\n{\n    /**\n     * 注册异常处理\n     * @return void\n     */\n    public static function register()\n    {\n        error_reporting(E_ALL);\n        set_error_handler([__CLASS__, 'appError']);\n        set_exception_handler([__CLASS__, 'appException']);\n        register_shutdown_function([__CLASS__, 'appShutdown']);\n    }\n\n    /**\n     * Exception Handler\n     * @param  \\Exception|\\Throwable $e\n     */\n    public static function appException($e)\n    {\n        if (!$e instanceof \\Exception) {\n            $e = new ThrowableError($e);\n        }\n\n        self::getExceptionHandler()->report($e);\n        if (IS_CLI) {\n            self::getExceptionHandler()->renderForConsole(new ConsoleOutput, $e);\n        } else {\n            self::getExceptionHandler()->render($e)->send();\n        }\n    }\n\n    /**\n     * Error Handler\n     * @param  integer $errno   错误编号\n     * @param  integer $errstr  详细错误信息\n     * @param  string  $errfile 出错的文件\n     * @param  integer $errline 出错行号\n     * @param array    $errcontext\n     * @throws ErrorException\n     */\n    public static function appError($errno, $errstr, $errfile = '', $errline = 0, $errcontext = [])\n    {\n        $exception = new ErrorException($errno, $errstr, $errfile, $errline, $errcontext);\n        if (error_reporting() & $errno) {\n            // 将错误信息托管至 think\\exception\\ErrorException\n            throw $exception;\n        } else {\n            self::getExceptionHandler()->report($exception);\n        }\n    }\n\n    /**\n     * Shutdown Handler\n     */\n    public static function appShutdown()\n    {\n        if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) {\n            // 将错误信息托管至think\\ErrorException\n            $exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']);\n\n            self::appException($exception);\n        }\n\n        // 写入日志\n        Log::save();\n    }\n\n    /**\n     * 确定错误类型是否致命\n     *\n     * @param  int $type\n     * @return bool\n     */\n    protected static function isFatal($type)\n    {\n        return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]);\n    }\n\n    /**\n     * Get an instance of the exception handler.\n     *\n     * @return Handle\n     */\n    public static function getExceptionHandler()\n    {\n        static $handle;\n        if (!$handle) {\n            // 异常处理handle\n            $class = Config::get('exception_handle');\n            if ($class && class_exists($class) && is_subclass_of($class, \"\\\\think\\\\exception\\\\Handle\")) {\n                $handle = new $class;\n            } else {\n                $handle = new Handle;\n            }\n        }\n        return $handle;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Exception.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nclass Exception extends \\Exception\n{\n\n    /**\n     * 保存异常页面显示的额外Debug数据\n     * @var array\n     */\n    protected $data = [];\n\n    /**\n     * 设置异常额外的Debug数据\n     * 数据将会显示为下面的格式\n     *\n     * Exception Data\n     * --------------------------------------------------\n     * Label 1\n     *   key1      value1\n     *   key2      value2\n     * Label 2\n     *   key1      value1\n     *   key2      value2\n     *\n     * @param string $label 数据分类，用于异常页面显示\n     * @param array  $data  需要显示的数据，必须为关联数组\n     */\n    final protected function setData($label, array $data)\n    {\n        $this->data[$label] = $data;\n    }\n\n    /**\n     * 获取异常额外Debug数据\n     * 主要用于输出到异常页面便于调试\n     * @return array 由setData设置的Debug数据\n     */\n    final public function getData()\n    {\n        return $this->data;\n    }\n    \n}\n"
  },
  {
    "path": "thinkphp/library/think/File.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse SplFileObject;\n\nclass File extends SplFileObject\n{\n    /**\n     * 错误信息\n     * @var string\n     */\n    private $error = '';\n    // 当前完整文件名\n    protected $filename;\n    // 上传文件名\n    protected $saveName;\n    // 文件上传命名规则\n    protected $rule = 'date';\n    // 文件上传验证规则\n    protected $validate = [];\n    // 单元测试\n    protected $isTest;\n    // 上传文件信息\n    protected $info;\n    // 文件hash信息\n    protected $hash = [];\n\n    public function __construct($filename, $mode = 'r')\n    {\n        parent::__construct($filename, $mode);\n        $this->filename = $this->getRealPath() ?: $this->getPathname();\n    }\n\n    /**\n     * 是否测试\n     * @param  bool   $test 是否测试\n     * @return $this\n     */\n    public function isTest($test = false)\n    {\n        $this->isTest = $test;\n        return $this;\n    }\n\n    /**\n     * 设置上传信息\n     * @param  array   $info 上传文件信息\n     * @return $this\n     */\n    public function setUploadInfo($info)\n    {\n        $this->info = $info;\n        return $this;\n    }\n\n    /**\n     * 获取上传文件的信息\n     * @param  string   $name\n     * @return array|string\n     */\n    public function getInfo($name = '')\n    {\n        return isset($this->info[$name]) ? $this->info[$name] : $this->info;\n    }\n\n    /**\n     * 获取上传文件的文件名\n     * @return string\n     */\n    public function getSaveName()\n    {\n        return $this->saveName;\n    }\n\n    /**\n     * 设置上传文件的保存文件名\n     * @param  string   $saveName\n     * @return $this\n     */\n    public function setSaveName($saveName)\n    {\n        $this->saveName = $saveName;\n        return $this;\n    }\n\n    /**\n     * 获取文件的哈希散列值\n     * @return $string\n     */\n    public function hash($type = 'sha1')\n    {\n        if (!isset($this->hash[$type])) {\n            $this->hash[$type] = hash_file($type, $this->filename);\n        }\n        return $this->hash[$type];\n    }\n\n    /**\n     * 检查目录是否可写\n     * @param  string   $path    目录\n     * @return boolean\n     */\n    protected function checkPath($path)\n    {\n        if (is_dir($path)) {\n            return true;\n        }\n\n        if (mkdir($path, 0755, true)) {\n            return true;\n        } else {\n            $this->error = \"目录 {$path} 创建失败！\";\n            return false;\n        }\n    }\n\n    /**\n     * 获取文件类型信息\n     * @return string\n     */\n    public function getMime()\n    {\n        $finfo = finfo_open(FILEINFO_MIME_TYPE);\n        return finfo_file($finfo, $this->filename);\n    }\n\n    /**\n     * 设置文件的命名规则\n     * @param  string   $rule    文件命名规则\n     * @return $this\n     */\n    public function rule($rule)\n    {\n        $this->rule = $rule;\n        return $this;\n    }\n\n    /**\n     * 设置上传文件的验证规则\n     * @param  array   $rule    验证规则\n     * @return $this\n     */\n    public function validate($rule = [])\n    {\n        $this->validate = $rule;\n        return $this;\n    }\n\n    /**\n     * 检测是否合法的上传文件\n     * @return bool\n     */\n    public function isValid()\n    {\n        if ($this->isTest) {\n            return is_file($this->filename);\n        }\n        return is_uploaded_file($this->filename);\n    }\n\n    /**\n     * 检测上传文件\n     * @param  array   $rule    验证规则\n     * @return bool\n     */\n    public function check($rule = [])\n    {\n        $rule = $rule ?: $this->validate;\n\n        /* 检查文件大小 */\n        if (isset($rule['size']) && !$this->checkSize($rule['size'])) {\n            $this->error = '上传文件大小不符！';\n            return false;\n        }\n\n        /* 检查文件Mime类型 */\n        if (isset($rule['type']) && !$this->checkMime($rule['type'])) {\n            $this->error = '上传文件MIME类型不允许！';\n            return false;\n        }\n\n        /* 检查文件后缀 */\n        if (isset($rule['ext']) && !$this->checkExt($rule['ext'])) {\n            $this->error = '上传文件后缀不允许';\n            return false;\n        }\n\n        /* 检查图像文件 */\n        if (!$this->checkImg()) {\n            $this->error = '非法图像文件！';\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * 检测上传文件后缀\n     * @param  array|string   $ext    允许后缀\n     * @return bool\n     */\n    public function checkExt($ext)\n    {\n        if (is_string($ext)) {\n            $ext = explode(',', $ext);\n        }\n        $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));\n        if (!in_array($extension, $ext)) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 检测图像文件\n     * @return bool\n     */\n    public function checkImg()\n    {\n        $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));\n        /* 对图像文件进行严格检测 */\n        if (in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']) && !in_array($this->getImageType($this->filename), [1, 2, 3, 4, 6])) {\n            return false;\n        }\n        return true;\n    }\n\n    // 判断图像类型\n    protected function getImageType($image)\n    {\n        if (function_exists('exif_imagetype')) {\n            return exif_imagetype($image);\n        } else {\n            $info = getimagesize($image);\n            return $info[2];\n        }\n    }\n\n    /**\n     * 检测上传文件大小\n     * @param  integer   $size    最大大小\n     * @return bool\n     */\n    public function checkSize($size)\n    {\n        if ($this->getSize() > $size) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 检测上传文件类型\n     * @param  array|string   $mime    允许类型\n     * @return bool\n     */\n    public function checkMime($mime)\n    {\n        if (is_string($mime)) {\n            $mime = explode(',', $mime);\n        }\n        if (!in_array(strtolower($this->getMime()), $mime)) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 移动文件\n     * @param  string           $path    保存路径\n     * @param  string|bool      $savename    保存的文件名 默认自动生成\n     * @param  boolean          $replace 同名文件是否覆盖\n     * @return false|File false-失败 否则返回File实例\n     */\n    public function move($path, $savename = true, $replace = true)\n    {\n        // 文件上传失败，捕获错误代码\n        if (!empty($this->info['error'])) {\n            $this->error($this->info['error']);\n            return false;\n        }\n\n        // 检测合法性\n        if (!$this->isValid()) {\n            $this->error = '非法上传文件';\n            return false;\n        }\n\n        // 验证上传\n        if (!$this->check()) {\n            return false;\n        }\n        $path = rtrim($path, DS) . DS;\n        // 文件保存命名规则\n        $saveName = $this->buildSaveName($savename);\n        $filename = $path . $saveName;\n\n        // 检测目录\n        if (false === $this->checkPath(dirname($filename))) {\n            return false;\n        }\n\n        /* 不覆盖同名文件 */\n        if (!$replace && is_file($filename)) {\n            $this->error = '存在同名文件' . $filename;\n            return false;\n        }\n\n        /* 移动文件 */\n        if ($this->isTest) {\n            rename($this->filename, $filename);\n        } elseif (!move_uploaded_file($this->filename, $filename)) {\n            $this->error = '文件上传保存错误！';\n            return false;\n        }\n        // 返回 File对象实例\n        $file = new self($filename);\n        $file->setSaveName($saveName);\n        $file->setUploadInfo($this->info);\n        return $file;\n    }\n\n    /**\n     * 获取保存文件名\n     * @param  string|bool   $savename    保存的文件名 默认自动生成\n     * @return string\n     */\n    protected function buildSaveName($savename)\n    {\n        if (true === $savename) {\n            // 自动生成文件名\n            if ($this->rule instanceof \\Closure) {\n                $savename = call_user_func_array($this->rule, [$this]);\n            } else {\n                switch ($this->rule) {\n                    case 'date':\n                        $savename = date('Ymd') . DS . md5(microtime(true));\n                        break;\n                    default:\n                        if (in_array($this->rule, hash_algos())) {\n                            $hash     = $this->hash($this->rule);\n                            $savename = substr($hash, 0, 2) . DS . substr($hash, 2);\n                        } elseif (is_callable($this->rule)) {\n                            $savename = call_user_func($this->rule);\n                        } else {\n                            $savename = date('Ymd') . DS . md5(microtime(true));\n                        }\n                }\n            }\n        } elseif ('' === $savename) {\n            $savename = $this->getInfo('name');\n        }\n        if (!strpos($savename, '.')) {\n            $savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION);\n        }\n        return $savename;\n    }\n\n    /**\n     * 获取错误代码信息\n     * @param int $errorNo  错误号\n     */\n    private function error($errorNo)\n    {\n        switch ($errorNo) {\n            case 1:\n            case 2:\n                $this->error = '上传文件大小超过了最大值！';\n                break;\n            case 3:\n                $this->error = '文件只有部分被上传！';\n                break;\n            case 4:\n                $this->error = '没有文件被上传！';\n                break;\n            case 6:\n                $this->error = '找不到临时文件夹！';\n                break;\n            case 7:\n                $this->error = '文件写入失败！';\n                break;\n            default:\n                $this->error = '未知上传错误！';\n        }\n    }\n\n    /**\n     * 获取错误信息\n     * @return mixed\n     */\n    public function getError()\n    {\n        return $this->error;\n    }\n\n    public function __call($method, $args)\n    {\n        return $this->hash($method);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Hook.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nclass Hook\n{\n\n    private static $tags = [];\n\n    /**\n     * 动态添加行为扩展到某个标签\n     * @param string    $tag 标签名称\n     * @param mixed     $behavior 行为名称\n     * @param bool      $first 是否放到开头执行\n     * @return void\n     */\n    public static function add($tag, $behavior, $first = false)\n    {\n        isset(self::$tags[$tag]) || self::$tags[$tag] = [];\n        if (is_array($behavior) && !is_callable($behavior)) {\n            if (!array_key_exists('_overlay', $behavior) || !$behavior['_overlay']) {\n                unset($behavior['_overlay']);\n                self::$tags[$tag] = array_merge(self::$tags[$tag], $behavior);\n            } else {\n                unset($behavior['_overlay']);\n                self::$tags[$tag] = $behavior;\n            }\n        } elseif ($first) {\n            array_unshift(self::$tags[$tag], $behavior);\n        } else {\n            self::$tags[$tag][] = $behavior;\n        }\n    }\n\n    /**\n     * 批量导入插件\n     * @param array        $tags 插件信息\n     * @param boolean     $recursive 是否递归合并\n     */\n    public static function import(array $tags, $recursive = true)\n    {\n        if ($recursive) {\n            foreach ($tags as $tag => $behavior) {\n                self::add($tag, $behavior);\n            }\n        } else {\n            self::$tags = $tags + self::$tags;\n        }\n    }\n\n    /**\n     * 获取插件信息\n     * @param string $tag 插件位置 留空获取全部\n     * @return array\n     */\n    public static function get($tag = '')\n    {\n        if (empty($tag)) {\n            //获取全部的插件信息\n            return self::$tags;\n        } else {\n            return array_key_exists($tag, self::$tags) ? self::$tags[$tag] : [];\n        }\n    }\n\n    /**\n     * 监听标签的行为\n     * @param string $tag    标签名称\n     * @param mixed  $params 传入参数\n     * @param mixed  $extra  额外参数\n     * @param bool   $once   只获取一个有效返回值\n     * @return mixed\n     */\n    public static function listen($tag, &$params = null, $extra = null, $once = false)\n    {\n        $results = [];\n        $tags    = static::get($tag);\n        foreach ($tags as $key => $name) {\n            $results[$key] = self::exec($name, $tag, $params, $extra);\n            if (false === $results[$key]) {\n                // 如果返回false 则中断行为执行\n                break;\n            } elseif (!is_null($results[$key]) && $once) {\n                break;\n            }\n        }\n        return $once ? end($results) : $results;\n    }\n\n    /**\n     * 执行某个行为\n     * @param mixed     $class 要执行的行为\n     * @param string    $tag 方法名（标签名）\n     * @param Mixed     $params 传人的参数\n     * @param mixed     $extra 额外参数\n     * @return mixed\n     */\n    public static function exec($class, $tag = '', &$params = null, $extra = null)\n    {\n        App::$debug && Debug::remark('behavior_start', 'time');\n        $method = Loader::parseName($tag, 1, false);\n        if ($class instanceof \\Closure) {\n            $result = call_user_func_array($class, [ & $params, $extra]);\n            $class  = 'Closure';\n        } elseif (is_array($class)) {\n            list($class, $method) = $class;\n\n            $result = (new $class())->$method($params, $extra);\n            $class  = $class . '->' . $method;\n        } elseif (is_object($class)) {\n            $result = $class->$method($params, $extra);\n            $class  = get_class($class);\n        } elseif (strpos($class, '::')) {\n            $result = call_user_func_array($class, [ & $params, $extra]);\n        } else {\n            $obj    = new $class();\n            $method = ($tag && is_callable([$obj, $method])) ? $method : 'run';\n            $result = $obj->$method($params, $extra);\n        }\n        if (App::$debug) {\n            Debug::remark('behavior_end', 'time');\n            Log::record('[ BEHAVIOR ] Run ' . $class . ' @' . $tag . ' [ RunTime:' . Debug::getRangeTime('behavior_start', 'behavior_end') . 's ]', 'info');\n        }\n        return $result;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/Lang.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nclass Lang\n{\n    // 语言数据\n    private static $lang = [];\n    // 语言作用域\n    private static $range = 'zh-cn';\n    // 语言自动侦测的变量\n    protected static $langDetectVar = 'lang';\n    // 语言Cookie变量\n    protected static $langCookieVar = 'think_var';\n    // 语言Cookie的过期时间\n    protected static $langCookieExpire = 3600;\n    // 允许语言列表\n    protected static $allowLangList = [];\n    // Accept-Language转义为对应语言包名称 系统默认配置\n    protected static $acceptLanguage = [\n        'zh-hans-cn' => 'zh-cn',\n    ];\n\n    // 设定当前的语言\n    public static function range($range = '')\n    {\n        if ('' == $range) {\n            return self::$range;\n        } else {\n            self::$range = $range;\n        }\n        return self::$range;\n    }\n\n    /**\n     * 设置语言定义(不区分大小写)\n     * @param string|array  $name 语言变量\n     * @param string        $value 语言值\n     * @param string        $range 语言作用域\n     * @return mixed\n     */\n    public static function set($name, $value = null, $range = '')\n    {\n        $range = $range ?: self::$range;\n        // 批量定义\n        if (!isset(self::$lang[$range])) {\n            self::$lang[$range] = [];\n        }\n        if (is_array($name)) {\n            return self::$lang[$range] = array_change_key_case($name) + self::$lang[$range];\n        } else {\n            return self::$lang[$range][strtolower($name)] = $value;\n        }\n    }\n\n    /**\n     * 加载语言定义(不区分大小写)\n     * @param string $file 语言文件\n     * @param string $range 语言作用域\n     * @return mixed\n     */\n    public static function load($file, $range = '')\n    {\n        $range = $range ?: self::$range;\n        if (!isset(self::$lang[$range])) {\n            self::$lang[$range] = [];\n        }\n        // 批量定义\n        if (is_string($file)) {\n            $file = [$file];\n        }\n        $lang = [];\n        foreach ($file as $_file) {\n            if (is_file($_file)) {\n                // 记录加载信息\n                App::$debug && Log::record('[ LANG ] ' . $_file, 'info');\n                $_lang = include $_file;\n                if (is_array($_lang)) {\n                    $lang = array_change_key_case($_lang) + $lang;\n                }\n            }\n        }\n        if (!empty($lang)) {\n            self::$lang[$range] = $lang + self::$lang[$range];\n        }\n        return self::$lang[$range];\n    }\n\n    /**\n     * 获取语言定义(不区分大小写)\n     * @param string|null   $name 语言变量\n     * @param string        $range 语言作用域\n     * @return mixed\n     */\n    public static function has($name, $range = '')\n    {\n        $range = $range ?: self::$range;\n        return isset(self::$lang[$range][strtolower($name)]);\n    }\n\n    /**\n     * 获取语言定义(不区分大小写)\n     * @param string|null   $name 语言变量\n     * @param array         $vars 变量替换\n     * @param string        $range 语言作用域\n     * @return mixed\n     */\n    public static function get($name = null, $vars = [], $range = '')\n    {\n        $range = $range ?: self::$range;\n        // 空参数返回所有定义\n        if (empty($name)) {\n            return self::$lang[$range];\n        }\n        $key   = strtolower($name);\n        $value = isset(self::$lang[$range][$key]) ? self::$lang[$range][$key] : $name;\n\n        // 变量解析\n        if (!empty($vars) && is_array($vars)) {\n            /**\n             * Notes:\n             * 为了检测的方便，数字索引的判断仅仅是参数数组的第一个元素的key为数字0\n             * 数字索引采用的是系统的 sprintf 函数替换，用法请参考 sprintf 函数\n             */\n            if (key($vars) === 0) {\n                // 数字索引解析\n                array_unshift($vars, $value);\n                $value = call_user_func_array('sprintf', $vars);\n            } else {\n                // 关联索引解析\n                $replace = array_keys($vars);\n                foreach ($replace as &$v) {\n                    $v = \"{:{$v}}\";\n                }\n                $value = str_replace($replace, $vars, $value);\n            }\n\n        }\n        return $value;\n    }\n\n    /**\n     * 自动侦测设置获取语言选择\n     * @return string\n     */\n    public static function detect()\n    {\n        // 自动侦测设置获取语言选择\n        $langSet = '';\n\n        if (isset($_GET[self::$langDetectVar])) {\n            // url中设置了语言变量\n            $langSet = strtolower($_GET[self::$langDetectVar]);\n        } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {\n            // 自动侦测浏览器语言\n            preg_match('/^([a-z\\d\\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);\n            $langSet     = strtolower($matches[1]);\n            $acceptLangs = Config::get('header_accept_lang');\n            if (isset($acceptLangs[$langSet])) {\n                $langSet = $acceptLangs[$langSet];\n            } elseif (isset(self::$acceptLanguage[$langSet])) {\n                $langSet = self::$acceptLanguage[$langSet];\n            }\n        }\n        if (empty(self::$allowLangList) || in_array($langSet, self::$allowLangList)) {\n            // 合法的语言\n            self::$range = $langSet ?: self::$range;\n        }\n        return self::$range;\n    }\n\n    /**\n     * 设置语言自动侦测的变量\n     * @param string $var 变量名称\n     * @return void\n     */\n    public static function setLangDetectVar($var)\n    {\n        self::$langDetectVar = $var;\n    }\n\n    /**\n     * 设置语言的cookie保存变量\n     * @param string $var 变量名称\n     * @return void\n     */\n    public static function setLangCookieVar($var)\n    {\n        self::$langCookieVar = $var;\n    }\n\n    /**\n     * 设置语言的cookie的过期时间\n     * @param string $expire 过期时间\n     * @return void\n     */\n    public static function setLangCookieExpire($expire)\n    {\n        self::$langCookieExpire = $expire;\n    }\n\n    /**\n     * 设置允许的语言列表\n     * @param array $list 语言列表\n     * @return void\n     */\n    public static function setAllowLangList($list)\n    {\n        self::$allowLangList = $list;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Loader.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\exception\\ClassNotFoundException;\n\nclass Loader\n{\n    protected static $instance = [];\n    // 类名映射\n    protected static $map = [];\n\n    // 命名空间别名\n    protected static $namespaceAlias = [];\n\n    // PSR-4\n    private static $prefixLengthsPsr4 = [];\n    private static $prefixDirsPsr4    = [];\n    private static $fallbackDirsPsr4  = [];\n\n    // PSR-0\n    private static $prefixesPsr0     = [];\n    private static $fallbackDirsPsr0 = [];\n\n    // 自动加载的文件\n    private static $autoloadFiles = [];\n\n    // 自动加载\n    public static function autoload($class)\n    {\n        // 检测命名空间别名\n        if (!empty(self::$namespaceAlias)) {\n            $namespace = dirname($class);\n            if (isset(self::$namespaceAlias[$namespace])) {\n                $original = self::$namespaceAlias[$namespace] . '\\\\' . basename($class);\n                if (class_exists($original)) {\n                    return class_alias($original, $class, false);\n                }\n            }\n        }\n\n        if ($file = self::findFile($class)) {\n\n            // Win环境严格区分大小写\n            if (IS_WIN && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {\n                return false;\n            }\n\n            __include_file($file);\n            return true;\n        }\n    }\n\n    /**\n     * 查找文件\n     * @param $class\n     * @return bool\n     */\n    private static function findFile($class)\n    {\n        if (!empty(self::$map[$class])) {\n            // 类库映射\n            return self::$map[$class];\n        }\n\n        // 查找 PSR-4\n        $logicalPathPsr4 = strtr($class, '\\\\', DS) . EXT;\n\n        $first = $class[0];\n        if (isset(self::$prefixLengthsPsr4[$first])) {\n            foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {\n                if (0 === strpos($class, $prefix)) {\n                    foreach (self::$prefixDirsPsr4[$prefix] as $dir) {\n                        if (is_file($file = $dir . DS . substr($logicalPathPsr4, $length))) {\n                            return $file;\n                        }\n                    }\n                }\n            }\n        }\n\n        // 查找 PSR-4 fallback dirs\n        foreach (self::$fallbackDirsPsr4 as $dir) {\n            if (is_file($file = $dir . DS . $logicalPathPsr4)) {\n                return $file;\n            }\n        }\n\n        // 查找 PSR-0\n        if (false !== $pos = strrpos($class, '\\\\')) {\n            // namespaced class name\n            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)\n            . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS);\n        } else {\n            // PEAR-like class name\n            $logicalPathPsr0 = strtr($class, '_', DS) . EXT;\n        }\n\n        if (isset(self::$prefixesPsr0[$first])) {\n            foreach (self::$prefixesPsr0[$first] as $prefix => $dirs) {\n                if (0 === strpos($class, $prefix)) {\n                    foreach ($dirs as $dir) {\n                        if (is_file($file = $dir . DS . $logicalPathPsr0)) {\n                            return $file;\n                        }\n                    }\n                }\n            }\n        }\n\n        // 查找 PSR-0 fallback dirs\n        foreach (self::$fallbackDirsPsr0 as $dir) {\n            if (is_file($file = $dir . DS . $logicalPathPsr0)) {\n                return $file;\n            }\n        }\n\n        return self::$map[$class] = false;\n    }\n\n    // 注册classmap\n    public static function addClassMap($class, $map = '')\n    {\n        if (is_array($class)) {\n            self::$map = array_merge(self::$map, $class);\n        } else {\n            self::$map[$class] = $map;\n        }\n    }\n\n    // 注册命名空间\n    public static function addNamespace($namespace, $path = '')\n    {\n        if (is_array($namespace)) {\n            foreach ($namespace as $prefix => $paths) {\n                self::addPsr4($prefix . '\\\\', rtrim($paths, DS), true);\n            }\n        } else {\n            self::addPsr4($namespace . '\\\\', rtrim($path, DS), true);\n        }\n    }\n\n    // 添加Ps0空间\n    private static function addPsr0($prefix, $paths, $prepend = false)\n    {\n        if (!$prefix) {\n            if ($prepend) {\n                self::$fallbackDirsPsr0 = array_merge(\n                    (array) $paths,\n                    self::$fallbackDirsPsr0\n                );\n            } else {\n                self::$fallbackDirsPsr0 = array_merge(\n                    self::$fallbackDirsPsr0,\n                    (array) $paths\n                );\n            }\n\n            return;\n        }\n\n        $first = $prefix[0];\n        if (!isset(self::$prefixesPsr0[$first][$prefix])) {\n            self::$prefixesPsr0[$first][$prefix] = (array) $paths;\n\n            return;\n        }\n        if ($prepend) {\n            self::$prefixesPsr0[$first][$prefix] = array_merge(\n                (array) $paths,\n                self::$prefixesPsr0[$first][$prefix]\n            );\n        } else {\n            self::$prefixesPsr0[$first][$prefix] = array_merge(\n                self::$prefixesPsr0[$first][$prefix],\n                (array) $paths\n            );\n        }\n    }\n\n    // 添加Psr4空间\n    private static function addPsr4($prefix, $paths, $prepend = false)\n    {\n        if (!$prefix) {\n            // Register directories for the root namespace.\n            if ($prepend) {\n                self::$fallbackDirsPsr4 = array_merge(\n                    (array) $paths,\n                    self::$fallbackDirsPsr4\n                );\n            } else {\n                self::$fallbackDirsPsr4 = array_merge(\n                    self::$fallbackDirsPsr4,\n                    (array) $paths\n                );\n            }\n        } elseif (!isset(self::$prefixDirsPsr4[$prefix])) {\n            // Register directories for a new namespace.\n            $length = strlen($prefix);\n            if ('\\\\' !== $prefix[$length - 1]) {\n                throw new \\InvalidArgumentException(\"A non-empty PSR-4 prefix must end with a namespace separator.\");\n            }\n            self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length;\n            self::$prefixDirsPsr4[$prefix]                = (array) $paths;\n        } elseif ($prepend) {\n            // Prepend directories for an already registered namespace.\n            self::$prefixDirsPsr4[$prefix] = array_merge(\n                (array) $paths,\n                self::$prefixDirsPsr4[$prefix]\n            );\n        } else {\n            // Append directories for an already registered namespace.\n            self::$prefixDirsPsr4[$prefix] = array_merge(\n                self::$prefixDirsPsr4[$prefix],\n                (array) $paths\n            );\n        }\n    }\n\n    // 注册命名空间别名\n    public static function addNamespaceAlias($namespace, $original = '')\n    {\n        if (is_array($namespace)) {\n            self::$namespaceAlias = array_merge(self::$namespaceAlias, $namespace);\n        } else {\n            self::$namespaceAlias[$namespace] = $original;\n        }\n    }\n\n    // 注册自动加载机制\n    public static function register($autoload = '')\n    {\n        // 注册系统自动加载\n        spl_autoload_register($autoload ?: 'think\\\\Loader::autoload', true, true);\n        // 注册命名空间定义\n        self::addNamespace([\n            'think'    => LIB_PATH . 'think' . DS,\n            'behavior' => LIB_PATH . 'behavior' . DS,\n            'traits'   => LIB_PATH . 'traits' . DS,\n        ]);\n        // 加载类库映射文件\n        if (is_file(RUNTIME_PATH . 'classmap' . EXT)) {\n            self::addClassMap(__include_file(RUNTIME_PATH . 'classmap' . EXT));\n        }\n\n        // Composer自动加载支持\n        if (is_dir(VENDOR_PATH . 'composer')) {\n            self::registerComposerLoader();\n        }\n\n        // 自动加载extend目录\n        self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS);\n    }\n\n    // 注册composer自动加载\n    private static function registerComposerLoader()\n    {\n        if (is_file(VENDOR_PATH . 'composer/autoload_namespaces.php')) {\n            $map = require VENDOR_PATH . 'composer/autoload_namespaces.php';\n            foreach ($map as $namespace => $path) {\n                self::addPsr0($namespace, $path);\n            }\n        }\n\n        if (is_file(VENDOR_PATH . 'composer/autoload_psr4.php')) {\n            $map = require VENDOR_PATH . 'composer/autoload_psr4.php';\n            foreach ($map as $namespace => $path) {\n                self::addPsr4($namespace, $path);\n            }\n        }\n\n        if (is_file(VENDOR_PATH . 'composer/autoload_classmap.php')) {\n            $classMap = require VENDOR_PATH . 'composer/autoload_classmap.php';\n            if ($classMap) {\n                self::addClassMap($classMap);\n            }\n        }\n\n        if (is_file(VENDOR_PATH . 'composer/autoload_files.php')) {\n            $includeFiles = require VENDOR_PATH . 'composer/autoload_files.php';\n            foreach ($includeFiles as $fileIdentifier => $file) {\n                if (empty(self::$autoloadFiles[$fileIdentifier])) {\n                    __require_file($file);\n                    self::$autoloadFiles[$fileIdentifier] = true;\n                }\n            }\n        }\n    }\n\n    /**\n     * 导入所需的类库 同java的Import 本函数有缓存功能\n     * @param string $class   类库命名空间字符串\n     * @param string $baseUrl 起始路径\n     * @param string $ext     导入的文件扩展名\n     * @return boolean\n     */\n    public static function import($class, $baseUrl = '', $ext = EXT)\n    {\n        static $_file = [];\n        $key          = $class . $baseUrl;\n        $class        = str_replace(['.', '#'], [DS, '.'], $class);\n        if (isset($_file[$key])) {\n            return true;\n        }\n\n        if (empty($baseUrl)) {\n            list($name, $class) = explode(DS, $class, 2);\n\n            if (isset(self::$prefixDirsPsr4[$name . '\\\\'])) {\n                // 注册的命名空间\n                $baseUrl = self::$prefixDirsPsr4[$name . '\\\\'];\n            } elseif ('@' == $name) {\n                //加载当前模块应用类库\n                $baseUrl = App::$modulePath;\n            } elseif (is_dir(EXTEND_PATH . $name)) {\n                $baseUrl = EXTEND_PATH . $name . DS;\n            } else {\n                // 加载其它模块的类库\n                $baseUrl = APP_PATH . $name . DS;\n            }\n        } elseif (substr($baseUrl, -1) != DS) {\n            $baseUrl .= DS;\n        }\n        // 如果类存在 则导入类库文件\n        if (is_array($baseUrl)) {\n            foreach ($baseUrl as $path) {\n                $filename = $path . DS . $class . $ext;\n                if (is_file($filename)) {\n                    break;\n                }\n            }\n        } else {\n            $filename = $baseUrl . $class . $ext;\n        }\n\n        if (!empty($filename) && is_file($filename)) {\n            // 开启调试模式Win环境严格区分大小写\n            if (IS_WIN && pathinfo($filename, PATHINFO_FILENAME) != pathinfo(realpath($filename), PATHINFO_FILENAME)) {\n                return false;\n            }\n            __include_file($filename);\n            $_file[$key] = true;\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 实例化（分层）模型\n     * @param string $name         Model名称\n     * @param string $layer        业务层名称\n     * @param bool   $appendSuffix 是否添加类名后缀\n     * @param string $common       公共模块名\n     * @return Object\n     * @throws ClassNotFoundException\n     */\n    public static function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common')\n    {\n        $guid = $name . $layer;\n        if (isset(self::$instance[$guid])) {\n            return self::$instance[$guid];\n        }\n        if (false !== strpos($name, '\\\\')) {\n            $class  = $name;\n            $module = Request::instance()->module();\n        } else {\n            if (strpos($name, '/')) {\n                list($module, $name) = explode('/', $name, 2);\n            } else {\n                $module = Request::instance()->module();\n            }\n            $class = self::parseClass($module, $layer, $name, $appendSuffix);\n        }\n        if (class_exists($class)) {\n            $model = new $class();\n        } else {\n            $class = str_replace('\\\\' . $module . '\\\\', '\\\\' . $common . '\\\\', $class);\n            if (class_exists($class)) {\n                $model = new $class();\n            } else {\n                throw new ClassNotFoundException('class not exists:' . $class, $class);\n            }\n        }\n        self::$instance[$guid] = $model;\n        return $model;\n    }\n\n    /**\n     * 实例化（分层）控制器 格式：[模块名/]控制器名\n     * @param string $name         资源地址\n     * @param string $layer        控制层名称\n     * @param bool   $appendSuffix 是否添加类名后缀\n     * @param string $empty        空控制器名称\n     * @return Object|false\n     * @throws ClassNotFoundException\n     */\n    public static function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')\n    {\n        if (false !== strpos($name, '\\\\')) {\n            $class  = $name;\n            $module = Request::instance()->module();\n        } else {\n            if (strpos($name, '/')) {\n                list($module, $name) = explode('/', $name);\n            } else {\n                $module = Request::instance()->module();\n            }\n            $class = self::parseClass($module, $layer, $name, $appendSuffix);\n        }\n        if (class_exists($class)) {\n            return App::invokeClass($class);\n        } elseif ($empty && class_exists($emptyClass = self::parseClass($module, $layer, $empty, $appendSuffix))) {\n            return new $emptyClass(Request::instance());\n        }\n    }\n\n    /**\n     * 实例化验证类 格式：[模块名/]验证器名\n     * @param string $name         资源地址\n     * @param string $layer        验证层名称\n     * @param bool   $appendSuffix 是否添加类名后缀\n     * @param string $common       公共模块名\n     * @return Object|false\n     * @throws ClassNotFoundException\n     */\n    public static function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common')\n    {\n        $name = $name ?: Config::get('default_validate');\n        if (empty($name)) {\n            return new Validate;\n        }\n        $guid = $name . $layer;\n        if (isset(self::$instance[$guid])) {\n            return self::$instance[$guid];\n        }\n        if (false !== strpos($name, '\\\\')) {\n            $class  = $name;\n            $module = Request::instance()->module();\n        } else {\n            if (strpos($name, '/')) {\n                list($module, $name) = explode('/', $name);\n            } else {\n                $module = Request::instance()->module();\n            }\n            $class = self::parseClass($module, $layer, $name, $appendSuffix);\n        }\n        if (class_exists($class)) {\n            $validate = new $class;\n        } else {\n            $class = str_replace('\\\\' . $module . '\\\\', '\\\\' . $common . '\\\\', $class);\n            if (class_exists($class)) {\n                $validate = new $class;\n            } else {\n                throw new ClassNotFoundException('class not exists:' . $class, $class);\n            }\n        }\n        self::$instance[$guid] = $validate;\n        return $validate;\n    }\n\n    /**\n     * 数据库初始化 并取得数据库类实例\n     * @param mixed         $config 数据库配置\n     * @param bool|string   $name 连接标识 true 强制重新连接\n     * @return \\think\\db\\Connection\n     */\n    public static function db($config = [], $name = false)\n    {\n        return Db::connect($config, $name);\n    }\n\n    /**\n     * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作\n     * @param string       $url          调用地址\n     * @param string|array $vars         调用参数 支持字符串和数组\n     * @param string       $layer        要调用的控制层名称\n     * @param bool         $appendSuffix 是否添加类名后缀\n     * @return mixed\n     */\n    public static function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)\n    {\n        $info   = pathinfo($url);\n        $action = $info['basename'];\n        $module = '.' != $info['dirname'] ? $info['dirname'] : Request::instance()->controller();\n        $class  = self::controller($module, $layer, $appendSuffix);\n        if ($class) {\n            if (is_scalar($vars)) {\n                if (strpos($vars, '=')) {\n                    parse_str($vars, $vars);\n                } else {\n                    $vars = [$vars];\n                }\n            }\n            return App::invokeMethod([$class, $action . Config::get('action_suffix')], $vars);\n        }\n    }\n\n    /**\n     * 字符串命名风格转换\n     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格\n     * @param string  $name 字符串\n     * @param integer $type 转换类型\n     * @param bool    $ucfirst 首字母是否大写（驼峰规则）\n     * @return string\n     */\n    public static function parseName($name, $type = 0, $ucfirst = true)\n    {\n        if ($type) {\n            $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {\n                return strtoupper($match[1]);\n            }, $name);\n            return $ucfirst ? ucfirst($name) : lcfirst($name);\n        } else {\n            return strtolower(trim(preg_replace(\"/[A-Z]/\", \"_\\\\0\", $name), \"_\"));\n        }\n    }\n\n    /**\n     * 解析应用类的类名\n     * @param string $module 模块名\n     * @param string $layer  层名 controller model ...\n     * @param string $name   类名\n     * @param bool   $appendSuffix\n     * @return string\n     */\n    public static function parseClass($module, $layer, $name, $appendSuffix = false)\n    {\n        $name  = str_replace(['/', '.'], '\\\\', $name);\n        $array = explode('\\\\', $name);\n        $class = self::parseName(array_pop($array), 1) . (App::$suffix || $appendSuffix ? ucfirst($layer) : '');\n        $path  = $array ? implode('\\\\', $array) . '\\\\' : '';\n        return App::$namespace . '\\\\' . ($module ? $module . '\\\\' : '') . $layer . '\\\\' . $path . $class;\n    }\n\n    /**\n     * 初始化类的实例\n     * @return void\n     */\n    public static function clearInstance()\n    {\n        self::$instance = [];\n    }\n}\n\n/**\n * 作用范围隔离\n *\n * @param $file\n * @return mixed\n */\nfunction __include_file($file)\n{\n    return include $file;\n}\n\nfunction __require_file($file)\n{\n    return require $file;\n}\n"
  },
  {
    "path": "thinkphp/library/think/Log.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\exception\\ClassNotFoundException;\n\n/**\n * Class Log\n * @package think\n *\n * @method void log($msg) static\n * @method void error($msg) static\n * @method void info($msg) static\n * @method void sql($msg) static\n * @method void notice($msg) static\n * @method void alert($msg) static\n */\nclass Log\n{\n    const LOG    = 'log';\n    const ERROR  = 'error';\n    const INFO   = 'info';\n    const SQL    = 'sql';\n    const NOTICE = 'notice';\n    const ALERT  = 'alert';\n    const DEBUG  = 'debug';\n\n    // 日志信息\n    protected static $log = [];\n    // 配置参数\n    protected static $config = [];\n    // 日志类型\n    protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert', 'debug'];\n    // 日志写入驱动\n    protected static $driver;\n\n    // 当前日志授权key\n    protected static $key;\n\n    /**\n     * 日志初始化\n     * @param array $config\n     */\n    public static function init($config = [])\n    {\n        $type         = isset($config['type']) ? $config['type'] : 'File';\n        $class        = false !== strpos($type, '\\\\') ? $type : '\\\\think\\\\log\\\\driver\\\\' . ucwords($type);\n        self::$config = $config;\n        unset($config['type']);\n        if (class_exists($class)) {\n            self::$driver = new $class($config);\n        } else {\n            throw new ClassNotFoundException('class not exists:' . $class, $class);\n        }\n        // 记录初始化信息\n        App::$debug && Log::record('[ LOG ] INIT ' . $type, 'info');\n    }\n\n    /**\n     * 获取日志信息\n     * @param string $type 信息类型\n     * @return array\n     */\n    public static function getLog($type = '')\n    {\n        return $type ? self::$log[$type] : self::$log;\n    }\n\n    /**\n     * 记录调试信息\n     * @param mixed  $msg  调试信息\n     * @param string $type 信息类型\n     * @return void\n     */\n    public static function record($msg, $type = 'log')\n    {\n        self::$log[$type][] = $msg;\n        if (IS_CLI) {\n            // 命令行下面日志写入改进\n            self::save();\n        }\n    }\n\n    /**\n     * 清空日志信息\n     * @return void\n     */\n    public static function clear()\n    {\n        self::$log = [];\n    }\n\n    /**\n     * 当前日志记录的授权key\n     * @param string $key 授权key\n     * @return void\n     */\n    public static function key($key)\n    {\n        self::$key = $key;\n    }\n\n    /**\n     * 检查日志写入权限\n     * @param array $config 当前日志配置参数\n     * @return bool\n     */\n    public static function check($config)\n    {\n        if (self::$key && !empty($config['allow_key']) && !in_array(self::$key, $config['allow_key'])) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 保存调试信息\n     * @return bool\n     */\n    public static function save()\n    {\n        if (!empty(self::$log)) {\n            if (is_null(self::$driver)) {\n                self::init(Config::get('log'));\n            }\n\n            if (!self::check(self::$config)) {\n                // 检测日志写入权限\n                return false;\n            }\n\n            if (empty(self::$config['level'])) {\n                // 获取全部日志\n                $log = self::$log;\n                if (!App::$debug && isset($log['debug'])) {\n                    unset($log['debug']);\n                }\n            } else {\n                // 记录允许级别\n                $log = [];\n                foreach (self::$config['level'] as $level) {\n                    if (isset(self::$log[$level])) {\n                        $log[$level] = self::$log[$level];\n                    }\n                }\n            }\n\n            $result = self::$driver->save($log);\n            if ($result) {\n                self::$log = [];\n            }\n            Hook::listen('log_write_done', $log);\n            return $result;\n        }\n        return true;\n    }\n\n    /**\n     * 实时写入日志信息 并支持行为\n     * @param mixed  $msg   调试信息\n     * @param string $type  信息类型\n     * @param bool   $force 是否强制写入\n     * @return bool\n     */\n    public static function write($msg, $type = 'log', $force = false)\n    {\n        $log = self::$log;\n        // 封装日志信息\n        if (true === $force || empty(self::$config['level'])) {\n            $log[$type][] = $msg;\n        } elseif (in_array($type, self::$config['level'])) {\n            $log[$type][] = $msg;\n        } else {\n            return false;\n        }\n\n        // 监听log_write\n        Hook::listen('log_write', $log);\n        if (is_null(self::$driver)) {\n            self::init(Config::get('log'));\n        }\n        // 写入日志\n        $result = self::$driver->save($log);\n        if ($result) {\n            self::$log = [];\n        }\n        return $result;\n    }\n\n    /**\n     * 静态调用\n     * @param $method\n     * @param $args\n     * @return mixed\n     */\n    public static function __callStatic($method, $args)\n    {\n        if (in_array($method, self::$type)) {\n            array_push($args, $method);\n            return call_user_func_array('\\\\think\\\\Log::record', $args);\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/Model.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse InvalidArgumentException;\nuse think\\db\\Query;\nuse think\\exception\\ValidateException;\nuse think\\model\\Collection as ModelCollection;\nuse think\\model\\Relation;\nuse think\\model\\relation\\BelongsTo;\nuse think\\model\\relation\\BelongsToMany;\nuse think\\model\\relation\\HasMany;\nuse think\\model\\relation\\HasManyThrough;\nuse think\\model\\relation\\HasOne;\nuse think\\model\\relation\\MorphMany;\nuse think\\model\\relation\\MorphOne;\nuse think\\model\\relation\\MorphTo;\n\n/**\n * Class Model\n * @package think\n * @mixin Query\n */\nabstract class Model implements \\JsonSerializable, \\ArrayAccess\n{\n    // 数据库查询对象池\n    protected static $links = [];\n    // 数据库配置\n    protected $connection = [];\n    // 父关联模型对象\n    protected $parent;\n    // 数据库查询对象\n    protected $query;\n    // 当前模型名称\n    protected $name;\n    // 数据表名称\n    protected $table;\n    // 当前类名称\n    protected $class;\n    // 回调事件\n    private static $event = [];\n    // 错误信息\n    protected $error;\n    // 字段验证规则\n    protected $validate;\n    // 数据表主键 复合主键使用数组定义 不设置则自动获取\n    protected $pk;\n    // 数据表字段信息 留空则自动获取\n    protected $field = [];\n    // 只读字段\n    protected $readonly = [];\n    // 显示属性\n    protected $visible = [];\n    // 隐藏属性\n    protected $hidden = [];\n    // 追加属性\n    protected $append = [];\n    // 数据信息\n    protected $data = [];\n    // 原始数据\n    protected $origin = [];\n    // 关联模型\n    protected $relation = [];\n\n    // 保存自动完成列表\n    protected $auto = [];\n    // 新增自动完成列表\n    protected $insert = [];\n    // 更新自动完成列表\n    protected $update = [];\n    // 是否需要自动写入时间戳 如果设置为字符串 则表示时间字段的类型\n    protected $autoWriteTimestamp;\n    // 创建时间字段\n    protected $createTime = 'create_time';\n    // 更新时间字段\n    protected $updateTime = 'update_time';\n    // 时间字段取出后的默认时间格式\n    protected $dateFormat;\n    // 字段类型或者格式转换\n    protected $type = [];\n    // 是否为更新数据\n    protected $isUpdate = false;\n    // 更新条件\n    protected $updateWhere;\n    // 验证失败是否抛出异常\n    protected $failException = false;\n    // 全局查询范围\n    protected $useGlobalScope = true;\n    // 是否采用批量验证\n    protected $batchValidate = false;\n    // 查询数据集对象\n    protected $resultSetType;\n    // 关联自动写入\n    protected $relationWrite;\n\n    /**\n     * 初始化过的模型.\n     *\n     * @var array\n     */\n    protected static $initialized = [];\n\n    /**\n     * 构造方法\n     * @access public\n     * @param array|object $data 数据\n     */\n    public function __construct($data = [])\n    {\n        if (is_object($data)) {\n            $this->data = get_object_vars($data);\n        } else {\n            $this->data = $data;\n        }\n        // 记录原始数据\n        $this->origin = $this->data;\n\n        // 当前类名\n        $this->class = get_called_class();\n\n        if (empty($this->name)) {\n            // 当前模型名\n            $name       = str_replace('\\\\', '/', $this->class);\n            $this->name = basename($name);\n            if (Config::get('class_suffix')) {\n                $suffix     = basename(dirname($name));\n                $this->name = substr($this->name, 0, -strlen($suffix));\n            }\n        }\n\n        if (is_null($this->autoWriteTimestamp)) {\n            // 自动写入时间戳\n            $this->autoWriteTimestamp = $this->getQuery()->getConfig('auto_timestamp');\n        }\n\n        if (is_null($this->dateFormat)) {\n            // 设置时间戳格式\n            $this->dateFormat = $this->getQuery()->getConfig('datetime_format');\n        }\n\n        if (is_null($this->resultSetType)) {\n            $this->resultSetType = $this->getQuery()->getConfig('resultset_type');\n        }\n        // 执行初始化操作\n        $this->initialize();\n    }\n\n    /**\n     * 创建模型的查询对象\n     * @access protected\n     * @return Query\n     */\n    protected function buildQuery()\n    {\n        // 合并数据库配置\n        if (!empty($this->connection)) {\n            if (is_array($this->connection)) {\n                $connection = array_merge(Config::get('database'), $this->connection);\n            } else {\n                $connection = $this->connection;\n            }\n        } else {\n            $connection = [];\n        }\n\n        $con = Db::connect($connection);\n        // 设置当前模型 确保查询返回模型对象\n        $queryClass = $this->query ?: $con->getConfig('query');\n        $query      = new $queryClass($con, $this->class);\n\n        // 设置当前数据表和模型名\n        if (!empty($this->table)) {\n            $query->setTable($this->table);\n        } else {\n            $query->name($this->name);\n        }\n\n        if (!empty($this->pk)) {\n            $query->pk($this->pk);\n        }\n\n        return $query;\n    }\n\n    /**\n     * 获取当前模型的查询对象\n     * @access public\n     * @param bool      $buildNewQuery  创建新的查询对象\n     * @return Query\n     */\n    public function getQuery($buildNewQuery = false)\n    {\n        if ($buildNewQuery) {\n            return $this->buildQuery();\n        } elseif (!isset(self::$links[$this->class])) {\n            // 创建模型查询对象\n            self::$links[$this->class] = $this->buildQuery();\n        }\n\n        return self::$links[$this->class];\n    }\n\n    /**\n     * 获取当前模型的数据库查询对象\n     * @access public\n     * @param bool $useBaseQuery 是否调用全局查询范围\n     * @param bool $buildNewQuery 创建新的查询对象\n     * @return Query\n     */\n    public function db($useBaseQuery = true, $buildNewQuery = true)\n    {\n        $query = $this->getQuery($buildNewQuery);\n\n        // 全局作用域\n        if ($useBaseQuery && method_exists($this, 'base')) {\n            call_user_func_array([$this, 'base'], [ & $query]);\n        }\n\n        // 返回当前模型的数据库查询对象\n        return $query;\n    }\n\n    /**\n     *  初始化模型\n     * @access protected\n     * @return void\n     */\n    protected function initialize()\n    {\n        $class = get_class($this);\n        if (!isset(static::$initialized[$class])) {\n            static::$initialized[$class] = true;\n            static::init();\n        }\n    }\n\n    /**\n     * 初始化处理\n     * @access protected\n     * @return void\n     */\n    protected static function init()\n    {\n    }\n\n    /**\n     * 设置父关联对象\n     * @access public\n     * @param Model $model  模型对象\n     * @return $this\n     */\n    public function setParent($model)\n    {\n        $this->parent = $model;\n\n        return $this;\n    }\n\n    /**\n     * 获取父关联对象\n     * @access public\n     * @return Model\n     */\n    public function getParent()\n    {\n        return $this->parent;\n    }\n\n    /**\n     * 设置数据对象值\n     * @access public\n     * @param mixed $data  数据或者属性名\n     * @param mixed $value 值\n     * @return $this\n     */\n    public function data($data, $value = null)\n    {\n        if (is_string($data)) {\n            $this->data[$data] = $value;\n        } else {\n            // 清空数据\n            $this->data = [];\n            if (is_object($data)) {\n                $data = get_object_vars($data);\n            }\n            if (true === $value) {\n                // 数据对象赋值\n                foreach ($data as $key => $value) {\n                    $this->setAttr($key, $value, $data);\n                }\n            } else {\n                $this->data = $data;\n            }\n        }\n        return $this;\n    }\n\n    /**\n     * 获取对象原始数据 如果不存在指定字段返回false\n     * @access public\n     * @param string $name 字段名 留空获取全部\n     * @return mixed\n     * @throws InvalidArgumentException\n     */\n    public function getData($name = null)\n    {\n        if (is_null($name)) {\n            return $this->data;\n        } elseif (array_key_exists($name, $this->data)) {\n            return $this->data[$name];\n        } elseif (array_key_exists($name, $this->relation)) {\n            return $this->relation[$name];\n        } else {\n            throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);\n        }\n    }\n\n    /**\n     * 是否需要自动写入时间字段\n     * @access public\n     * @param bool $auto\n     * @return $this\n     */\n    public function isAutoWriteTimestamp($auto)\n    {\n        $this->autoWriteTimestamp = $auto;\n        return $this;\n    }\n\n    /**\n     * 修改器 设置数据对象值\n     * @access public\n     * @param string $name  属性名\n     * @param mixed  $value 属性值\n     * @param array  $data  数据\n     * @return $this\n     */\n    public function setAttr($name, $value, $data = [])\n    {\n        if (is_null($value) && $this->autoWriteTimestamp && in_array($name, [$this->createTime, $this->updateTime])) {\n            // 自动写入的时间戳字段\n            $value = $this->autoWriteTimestamp($name);\n        } else {\n            // 检测修改器\n            $method = 'set' . Loader::parseName($name, 1) . 'Attr';\n            if (method_exists($this, $method)) {\n                $value = $this->$method($value, array_merge($this->data, $data), $this->relation);\n            } elseif (isset($this->type[$name])) {\n                // 类型转换\n                $value = $this->writeTransform($value, $this->type[$name]);\n            }\n        }\n\n        // 设置数据对象属性\n        $this->data[$name] = $value;\n        return $this;\n    }\n\n    /**\n     * 获取当前模型的关联模型数据\n     * @access public\n     * @param string $name 关联方法名\n     * @return mixed\n     */\n    public function getRelation($name = null)\n    {\n        if (is_null($name)) {\n            return $this->relation;\n        } elseif (array_key_exists($name, $this->relation)) {\n            return $this->relation[$name];\n        } else {\n            return;\n        }\n    }\n\n    /**\n     * 设置关联数据对象值\n     * @access public\n     * @param string $name  属性名\n     * @param mixed  $value 属性值\n     * @return $this\n     */\n    public function setRelation($name, $value)\n    {\n        $this->relation[$name] = $value;\n        return $this;\n    }\n\n    /**\n     * 自动写入时间戳\n     * @access public\n     * @param string $name 时间戳字段\n     * @return mixed\n     */\n    protected function autoWriteTimestamp($name)\n    {\n        if (isset($this->type[$name])) {\n            $type = $this->type[$name];\n            if (strpos($type, ':')) {\n                list($type, $param) = explode(':', $type, 2);\n            }\n            switch ($type) {\n                case 'datetime':\n                case 'date':\n                    $format = !empty($param) ? $param : $this->dateFormat;\n                    $value  = $this->formatDateTime(time(), $format);\n                    break;\n                case 'timestamp':\n                case 'integer':\n                default:\n                    $value = time();\n                    break;\n            }\n        } elseif (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [\n            'datetime',\n            'date',\n            'timestamp',\n        ])\n        ) {\n            $value = $this->formatDateTime(time(), $this->dateFormat);\n        } else {\n            $value = $this->formatDateTime(time(), $this->dateFormat, true);\n        }\n        return $value;\n    }\n\n    /**\n     * 时间日期字段格式化处理\n     * @access public\n     * @param mixed $time      时间日期表达式\n     * @param mixed $format    日期格式\n     * @param bool  $timestamp 是否进行时间戳转换\n     * @return mixed\n     */\n    protected function formatDateTime($time, $format, $timestamp = false)\n    {\n        if (false !== strpos($format, '\\\\')) {\n            $time = new $format($time);\n        } elseif (!$timestamp && false !== $format) {\n            $time = date($format, $time);\n        }\n        return $time;\n    }\n\n    /**\n     * 数据写入 类型转换\n     * @access public\n     * @param mixed        $value 值\n     * @param string|array $type  要转换的类型\n     * @return mixed\n     */\n    protected function writeTransform($value, $type)\n    {\n        if (is_null($value)) {\n            return;\n        }\n\n        if (is_array($type)) {\n            list($type, $param) = $type;\n        } elseif (strpos($type, ':')) {\n            list($type, $param) = explode(':', $type, 2);\n        }\n        switch ($type) {\n            case 'integer':\n                $value = (int) $value;\n                break;\n            case 'float':\n                if (empty($param)) {\n                    $value = (float) $value;\n                } else {\n                    $value = (float) number_format($value, $param, '.', '');\n                }\n                break;\n            case 'boolean':\n                $value = (bool) $value;\n                break;\n            case 'timestamp':\n                if (!is_numeric($value)) {\n                    $value = strtotime($value);\n                }\n                break;\n            case 'datetime':\n                $format = !empty($param) ? $param : $this->dateFormat;\n                $value  = is_numeric($value) ? $value : strtotime($value);\n                $value  = $this->formatDateTime($value, $format);\n                break;\n            case 'object':\n                if (is_object($value)) {\n                    $value = json_encode($value, JSON_FORCE_OBJECT);\n                }\n                break;\n            case 'array':\n                $value = (array) $value;\n            case 'json':\n                $option = !empty($param) ? (int) $param : JSON_UNESCAPED_UNICODE;\n                $value  = json_encode($value, $option);\n                break;\n            case 'serialize':\n                $value = serialize($value);\n                break;\n\n        }\n        return $value;\n    }\n\n    /**\n     * 获取器 获取数据对象的值\n     * @access public\n     * @param string $name 名称\n     * @return mixed\n     * @throws InvalidArgumentException\n     */\n    public function getAttr($name)\n    {\n        try {\n            $notFound = false;\n            $value    = $this->getData($name);\n        } catch (InvalidArgumentException $e) {\n            $notFound = true;\n            $value    = null;\n        }\n\n        // 检测属性获取器\n        $method = 'get' . Loader::parseName($name, 1) . 'Attr';\n        if (method_exists($this, $method)) {\n            $value = $this->$method($value, $this->data, $this->relation);\n        } elseif (isset($this->type[$name])) {\n            // 类型转换\n            $value = $this->readTransform($value, $this->type[$name]);\n        } elseif (in_array($name, [$this->createTime, $this->updateTime])) {\n            if (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [\n                'datetime',\n                'date',\n                'timestamp',\n            ])\n            ) {\n                $value = $this->formatDateTime(strtotime($value), $this->dateFormat);\n            } else {\n                $value = $this->formatDateTime($value, $this->dateFormat);\n            }\n        } elseif ($notFound) {\n            $relation = Loader::parseName($name, 1, false);\n            if (method_exists($this, $relation)) {\n                $modelRelation = $this->$relation();\n                // 不存在该字段 获取关联数据\n                $value = $this->getRelationData($modelRelation);\n                // 保存关联对象值\n                $this->relation[$name] = $value;\n            } else {\n                throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);\n            }\n        }\n        return $value;\n    }\n\n    /**\n     * 获取关联模型数据\n     * @access public\n     * @param Relation        $modelRelation 模型关联对象\n     * @return mixed\n     */\n    protected function getRelationData(Relation $modelRelation)\n    {\n        if ($this->parent && get_class($this->parent) == $modelRelation->getModel()) {\n            $value = $this->parent;\n        } else {\n            // 首先获取关联数据\n            $value = $modelRelation->getRelation();\n        }\n        return $value;\n    }\n\n    /**\n     * 数据读取 类型转换\n     * @access public\n     * @param mixed        $value 值\n     * @param string|array $type  要转换的类型\n     * @return mixed\n     */\n    protected function readTransform($value, $type)\n    {\n        if (is_null($value)) {\n            return;\n        }\n\n        if (is_array($type)) {\n            list($type, $param) = $type;\n        } elseif (strpos($type, ':')) {\n            list($type, $param) = explode(':', $type, 2);\n        }\n        switch ($type) {\n            case 'integer':\n                $value = (int) $value;\n                break;\n            case 'float':\n                if (empty($param)) {\n                    $value = (float) $value;\n                } else {\n                    $value = (float) number_format($value, $param, '.', '');\n                }\n                break;\n            case 'boolean':\n                $value = (bool) $value;\n                break;\n            case 'timestamp':\n                if (!is_null($value)) {\n                    $format = !empty($param) ? $param : $this->dateFormat;\n                    $value  = $this->formatDateTime($value, $format);\n                }\n                break;\n            case 'datetime':\n                if (!is_null($value)) {\n                    $format = !empty($param) ? $param : $this->dateFormat;\n                    $value  = $this->formatDateTime(strtotime($value), $format);\n                }\n                break;\n            case 'json':\n                $value = json_decode($value, true);\n                break;\n            case 'array':\n                $value = empty($value) ? [] : json_decode($value, true);\n                break;\n            case 'object':\n                $value = empty($value) ? new \\stdClass() : json_decode($value);\n                break;\n            case 'serialize':\n                $value = unserialize($value);\n                break;\n            default:\n                if (false !== strpos($type, '\\\\')) {\n                    // 对象类型\n                    $value = new $type($value);\n                }\n        }\n        return $value;\n    }\n\n    /**\n     * 设置需要追加的输出属性\n     * @access public\n     * @param array $append   属性列表\n     * @param bool  $override 是否覆盖\n     * @return $this\n     */\n    public function append($append = [], $override = false)\n    {\n        $this->append = $override ? $append : array_merge($this->append, $append);\n        return $this;\n    }\n\n    /**\n     * 设置附加关联对象的属性\n     * @access public\n     * @param string       $relation 关联方法\n     * @param string|array $append   追加属性名\n     * @return $this\n     * @throws Exception\n     */\n    public function appendRelationAttr($relation, $append)\n    {\n        if (is_string($append)) {\n            $append = explode(',', $append);\n        }\n\n        $relation = Loader::parseName($relation, 1, false);\n\n        // 获取关联数据\n        if (isset($this->relation[$relation])) {\n            $model = $this->relation[$relation];\n        } else {\n            $model = $this->getRelationData($this->$relation());\n        }\n\n        if ($model instanceof Model) {\n            foreach ($append as $key => $attr) {\n                $key = is_numeric($key) ? $attr : $key;\n                if (isset($this->data[$key])) {\n                    throw new Exception('bind attr has exists:' . $key);\n                } else {\n                    $this->data[$key] = $model->$attr;\n                }\n            }\n        }\n        return $this;\n    }\n\n    /**\n     * 设置需要隐藏的输出属性\n     * @access public\n     * @param array $hidden   属性列表\n     * @param bool  $override 是否覆盖\n     * @return $this\n     */\n    public function hidden($hidden = [], $override = false)\n    {\n        $this->hidden = $override ? $hidden : array_merge($this->hidden, $hidden);\n        return $this;\n    }\n\n    /**\n     * 设置需要输出的属性\n     * @access public\n     * @param array $visible\n     * @param bool  $override 是否覆盖\n     * @return $this\n     */\n    public function visible($visible = [], $override = false)\n    {\n        $this->visible = $override ? $visible : array_merge($this->visible, $visible);\n        return $this;\n    }\n\n    /**\n     * 解析隐藏及显示属性\n     * @access protected\n     * @param array $attrs  属性\n     * @param array $result 结果集\n     * @param bool  $visible\n     * @return array\n     */\n    protected function parseAttr($attrs, &$result, $visible = true)\n    {\n        $array = [];\n        foreach ($attrs as $key => $val) {\n            if (is_array($val)) {\n                if ($visible) {\n                    $array[] = $key;\n                }\n                $result[$key] = $val;\n            } elseif (strpos($val, '.')) {\n                list($key, $name) = explode('.', $val);\n                if ($visible) {\n                    $array[] = $key;\n                }\n                $result[$key][] = $name;\n            } else {\n                $array[] = $val;\n            }\n        }\n        return $array;\n    }\n\n    /**\n     * 转换子模型对象\n     * @access protected\n     * @param Model|ModelCollection $model\n     * @param                  $visible\n     * @param                  $hidden\n     * @param                  $key\n     * @return array\n     */\n    protected function subToArray($model, $visible, $hidden, $key)\n    {\n        // 关联模型对象\n        if (isset($visible[$key])) {\n            $model->visible($visible[$key]);\n        } elseif (isset($hidden[$key])) {\n            $model->hidden($hidden[$key]);\n        }\n        return $model->toArray();\n    }\n\n    /**\n     * 转换当前模型对象为数组\n     * @access public\n     * @return array\n     */\n    public function toArray()\n    {\n        $item    = [];\n        $visible = [];\n        $hidden  = [];\n\n        $data = array_merge($this->data, $this->relation);\n\n        // 过滤属性\n        if (!empty($this->visible)) {\n            $array = $this->parseAttr($this->visible, $visible);\n            $data  = array_intersect_key($data, array_flip($array));\n        } elseif (!empty($this->hidden)) {\n            $array = $this->parseAttr($this->hidden, $hidden, false);\n            $data  = array_diff_key($data, array_flip($array));\n        }\n\n        foreach ($data as $key => $val) {\n            if ($val instanceof Model || $val instanceof ModelCollection) {\n                // 关联模型对象\n                $item[$key] = $this->subToArray($val, $visible, $hidden, $key);\n            } elseif (is_array($val) && reset($val) instanceof Model) {\n                // 关联模型数据集\n                $arr = [];\n                foreach ($val as $k => $value) {\n                    $arr[$k] = $this->subToArray($value, $visible, $hidden, $key);\n                }\n                $item[$key] = $arr;\n            } else {\n                // 模型属性\n                $item[$key] = $this->getAttr($key);\n            }\n        }\n        // 追加属性（必须定义获取器）\n        if (!empty($this->append)) {\n            foreach ($this->append as $key => $name) {\n                if (is_array($name)) {\n                    // 追加关联对象属性\n                    $relation   = $this->getAttr($key);\n                    $item[$key] = $relation->append($name)->toArray();\n                } elseif (strpos($name, '.')) {\n                    list($key, $attr) = explode('.', $name);\n                    // 追加关联对象属性\n                    $relation   = $this->getAttr($key);\n                    $item[$key] = $relation->append([$attr])->toArray();\n                } else {\n                    $item[$name] = $this->getAttr($name);\n                }\n            }\n        }\n        return !empty($item) ? $item : [];\n    }\n\n    /**\n     * 转换当前模型对象为JSON字符串\n     * @access public\n     * @param integer $options json参数\n     * @return string\n     */\n    public function toJson($options = JSON_UNESCAPED_UNICODE)\n    {\n        return json_encode($this->toArray(), $options);\n    }\n\n    /**\n     * 移除当前模型的关联属性\n     * @access public\n     * @return $this\n     */\n    public function removeRelation()\n    {\n        $this->relation = [];\n        return $this;\n    }\n\n    /**\n     * 转换当前模型数据集为数据集对象\n     * @access public\n     * @param array|\\think\\Collection $collection 数据集\n     * @return \\think\\Collection\n     */\n    public function toCollection($collection)\n    {\n        if ($this->resultSetType) {\n            if ('collection' == $this->resultSetType) {\n                $collection = new ModelCollection($collection);\n            } elseif (false !== strpos($this->resultSetType, '\\\\')) {\n                $class      = $this->resultSetType;\n                $collection = new $class($collection);\n            }\n        }\n        return $collection;\n    }\n\n    /**\n     * 关联数据一起更新\n     * @access public\n     * @param mixed $relation 关联\n     * @return $this\n     */\n    public function together($relation)\n    {\n        if (is_string($relation)) {\n            $relation = explode(',', $relation);\n        }\n        $this->relationWrite = $relation;\n        return $this;\n    }\n\n    /**\n     * 获取模型对象的主键\n     * @access public\n     * @param string $name 模型名\n     * @return mixed\n     */\n    public function getPk($name = '')\n    {\n        if (!empty($name)) {\n            $table = $this->getQuery()->getTable($name);\n            return $this->getQuery()->getPk($table);\n        } elseif (empty($this->pk)) {\n            $this->pk = $this->getQuery()->getPk();\n        }\n        return $this->pk;\n    }\n\n    /**\n     * 判断一个字段名是否为主键字段\n     * @access public\n     * @param string $key 名称\n     * @return bool\n     */\n    protected function isPk($key)\n    {\n        $pk = $this->getPk();\n        if (is_string($pk) && $pk == $key) {\n            return true;\n        } elseif (is_array($pk) && in_array($key, $pk)) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 保存当前数据对象\n     * @access public\n     * @param array  $data     数据\n     * @param array  $where    更新条件\n     * @param string $sequence 自增序列名\n     * @return integer|false\n     */\n    public function save($data = [], $where = [], $sequence = null)\n    {\n        if (!empty($data)) {\n            // 数据自动验证\n            if (!$this->validateData($data)) {\n                return false;\n            }\n            // 数据对象赋值\n            foreach ($data as $key => $value) {\n                $this->setAttr($key, $value, $data);\n            }\n            if (!empty($where)) {\n                $this->isUpdate = true;\n            }\n        }\n\n        // 自动关联写入\n        if (!empty($this->relationWrite)) {\n            $relation = [];\n            foreach ($this->relationWrite as $key => $name) {\n                if (is_array($name)) {\n                    if (key($name) === 0) {\n                        $relation[$key] = [];\n                        foreach ($name as $val) {\n                            if (isset($this->data[$val])) {\n                                $relation[$key][$val] = $this->data[$val];\n                                unset($this->data[$val]);\n                            }\n                        }\n                    } else {\n                        $relation[$key] = $name;\n                    }\n                } elseif (isset($this->relation[$name])) {\n                    $relation[$name] = $this->relation[$name];\n                } elseif (isset($this->data[$name])) {\n                    $relation[$name] = $this->data[$name];\n                    unset($this->data[$name]);\n                }\n            }\n        }\n\n        // 数据自动完成\n        $this->autoCompleteData($this->auto);\n\n        // 事件回调\n        if (false === $this->trigger('before_write', $this)) {\n            return false;\n        }\n        $pk = $this->getPk();\n        if ($this->isUpdate) {\n            // 自动更新\n            $this->autoCompleteData($this->update);\n\n            // 事件回调\n            if (false === $this->trigger('before_update', $this)) {\n                return false;\n            }\n\n            // 获取有更新的数据\n            $data = $this->getChangedData();\n\n            if (empty($data) || (count($data) == 1 && is_string($pk) && isset($data[$pk]))) {\n                // 关联更新\n                if (isset($relation)) {\n                    $this->autoRelationUpdate($relation);\n                }\n                return 0;\n            } elseif ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {\n                // 自动写入更新时间\n                $data[$this->updateTime]       = $this->autoWriteTimestamp($this->updateTime);\n                $this->data[$this->updateTime] = $data[$this->updateTime];\n            }\n\n            if (empty($where) && !empty($this->updateWhere)) {\n                $where = $this->updateWhere;\n            }\n\n            // 保留主键数据\n            foreach ($this->data as $key => $val) {\n                if ($this->isPk($key)) {\n                    $data[$key] = $val;\n                }\n            }\n\n            if (is_string($pk) && isset($data[$pk])) {\n                if (!isset($where[$pk])) {\n                    unset($where);\n                    $where[$pk] = $data[$pk];\n                }\n                unset($data[$pk]);\n            }\n\n            // 检测字段\n            $allowFields = $this->checkAllowField(array_merge($this->auto, $this->update));\n\n            // 模型更新\n            if (!empty($allowFields)) {\n                $result = $this->getQuery()->where($where)->strict(false)->field($allowFields)->update($data);\n            } else {\n                $result = $this->getQuery()->where($where)->update($data);\n            }\n\n            // 关联更新\n            if (isset($relation)) {\n                $this->autoRelationUpdate($relation);\n            }\n\n            // 更新回调\n            $this->trigger('after_update', $this);\n\n        } else {\n            // 自动写入\n            $this->autoCompleteData($this->insert);\n\n            // 自动写入创建时间和更新时间\n            if ($this->autoWriteTimestamp) {\n                if ($this->createTime && !isset($this->data[$this->createTime])) {\n                    $this->data[$this->createTime] = $this->autoWriteTimestamp($this->createTime);\n                }\n                if ($this->updateTime && !isset($this->data[$this->updateTime])) {\n                    $this->data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);\n                }\n            }\n\n            if (false === $this->trigger('before_insert', $this)) {\n                return false;\n            }\n\n            // 检测字段\n            $allowFields = $this->checkAllowField(array_merge($this->auto, $this->insert));\n            if (!empty($allowFields)) {\n                $result = $this->getQuery()->strict(false)->field($allowFields)->insert($this->data);\n            } else {\n                $result = $this->getQuery()->insert($this->data);\n            }\n\n            // 获取自动增长主键\n            if ($result && is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) {\n                $insertId = $this->getQuery()->getLastInsID($sequence);\n                if ($insertId) {\n                    $this->data[$pk] = $insertId;\n                }\n            }\n\n            // 关联写入\n            if (isset($relation)) {\n                foreach ($relation as $name => $val) {\n                    $method = Loader::parseName($name, 1, false);\n                    $this->$method()->save($val);\n                }\n            }\n\n            // 标记为更新\n            $this->isUpdate = true;\n\n            // 新增回调\n            $this->trigger('after_insert', $this);\n        }\n        // 写入回调\n        $this->trigger('after_write', $this);\n\n        // 重新记录原始数据\n        $this->origin = $this->data;\n\n        return $result;\n    }\n\n    protected function checkAllowField($auto = [])\n    {\n        if (true === $this->field) {\n            $this->field = $this->getQuery()->getTableInfo('', 'fields');\n            $field       = $this->field;\n        } elseif (!empty($this->field)) {\n            $field = array_merge($this->field, $auto);\n        } else {\n            $field = [];\n\n        }\n\n        return $field;\n    }\n\n    protected function autoRelationUpdate($relation)\n    {\n        foreach ($relation as $name => $val) {\n            if ($val instanceof Model) {\n                $val->save();\n            } else {\n                unset($this->data[$name]);\n                $model = $this->getAttr($name);\n                if ($model instanceof Model) {\n                    $model->save($val);\n                }\n            }\n        }\n    }\n\n    /**\n     * 获取变化的数据 并排除只读数据\n     * @access public\n     * @return array\n     */\n    public function getChangedData()\n    {\n        $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) {\n            if ((empty($b) || empty($b)) && $a !== $b) {\n                return 1;\n            }\n            return is_object($a) || $a != $b ? 1 : 0;\n        });\n\n        if (!empty($this->readonly)) {\n            // 只读字段不允许更新\n            foreach ($this->readonly as $key => $field) {\n                if (isset($data[$field])) {\n                    unset($data[$field]);\n                }\n            }\n        }\n\n        return $data;\n    }\n\n    /**\n     * 字段值(延迟)增长\n     * @access public\n     * @param string  $field    字段名\n     * @param integer $step     增长值\n     * @param integer $lazyTime 延时时间(s)\n     * @return integer|true\n     * @throws Exception\n     */\n    public function setInc($field, $step = 1, $lazyTime = 0)\n    {\n        // 删除条件\n        $pk = $this->getPk();\n\n        if (is_string($pk) && isset($this->data[$pk])) {\n            $where = [$pk => $this->data[$pk]];\n        } elseif (!empty($this->updateWhere)) {\n            $where = $this->updateWhere;\n        } else {\n            $where = null;\n        }\n\n        $result = $this->getQuery()->where($where)->setInc($field, $step, $lazyTime);\n        if (true !== $result) {\n            $this->data[$field] += $step;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 字段值(延迟)增长\n     * @access public\n     * @param string  $field    字段名\n     * @param integer $step     增长值\n     * @param integer $lazyTime 延时时间(s)\n     * @return integer|true\n     * @throws Exception\n     */\n    public function setDec($field, $step = 1, $lazyTime = 0)\n    {\n        // 删除条件\n        $pk = $this->getPk();\n\n        if (is_string($pk) && isset($this->data[$pk])) {\n            $where = [$pk => $this->data[$pk]];\n        } elseif (!empty($this->updateWhere)) {\n            $where = $this->updateWhere;\n        } else {\n            $where = null;\n        }\n\n        $result = $this->getQuery()->where($where)->setDec($field, $step, $lazyTime);\n        if (true !== $result) {\n            $this->data[$field] -= $step;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 保存多个数据到当前数据对象\n     * @access public\n     * @param array   $dataSet 数据\n     * @param boolean $replace 是否自动识别更新和写入\n     * @return array|false\n     * @throws \\Exception\n     */\n    public function saveAll($dataSet, $replace = true)\n    {\n        if ($this->validate) {\n            // 数据批量验证\n            $validate = $this->validate;\n            foreach ($dataSet as $data) {\n                if (!$this->validateData($data, $validate)) {\n                    return false;\n                }\n            }\n        }\n\n        $result = [];\n        $db     = $this->getQuery();\n        $db->startTrans();\n        try {\n            $pk = $this->getPk();\n            if (is_string($pk) && $replace) {\n                $auto = true;\n            }\n            foreach ($dataSet as $key => $data) {\n                if (!empty($auto) && isset($data[$pk])) {\n                    $result[$key] = self::update($data, [], $this->field);\n                } else {\n                    $result[$key] = self::create($data, $this->field);\n                }\n            }\n            $db->commit();\n            return $result;\n        } catch (\\Exception $e) {\n            $db->rollback();\n            throw $e;\n        }\n    }\n\n    /**\n     * 设置允许写入的字段\n     * @access public\n     * @param mixed $field 允许写入的字段 如果为true只允许写入数据表字段\n     * @return $this\n     */\n    public function allowField($field)\n    {\n        if (is_string($field)) {\n            $field = explode(',', $field);\n        }\n        $this->field = $field;\n        return $this;\n    }\n\n    /**\n     * 设置只读字段\n     * @access public\n     * @param mixed $field 只读字段\n     * @return $this\n     */\n    public function readonly($field)\n    {\n        if (is_string($field)) {\n            $field = explode(',', $field);\n        }\n        $this->readonly = $field;\n        return $this;\n    }\n\n    /**\n     * 是否为更新数据\n     * @access public\n     * @param bool  $update\n     * @param mixed $where\n     * @return $this\n     */\n    public function isUpdate($update = true, $where = null)\n    {\n        $this->isUpdate = $update;\n        if (!empty($where)) {\n            $this->updateWhere = $where;\n        }\n        return $this;\n    }\n\n    /**\n     * 数据自动完成\n     * @access public\n     * @param array $auto 要自动更新的字段列表\n     * @return void\n     */\n    protected function autoCompleteData($auto = [])\n    {\n        foreach ($auto as $field => $value) {\n            if (is_integer($field)) {\n                $field = $value;\n                $value = null;\n            }\n\n            if (!isset($this->data[$field])) {\n                $default = null;\n            } else {\n                $default = $this->data[$field];\n            }\n\n            $this->setAttr($field, !is_null($value) ? $value : $default);\n        }\n    }\n\n    /**\n     * 删除当前的记录\n     * @access public\n     * @return integer\n     */\n    public function delete()\n    {\n        if (false === $this->trigger('before_delete', $this)) {\n            return false;\n        }\n\n        // 删除条件\n        $pk = $this->getPk();\n        if (is_string($pk) && isset($this->data[$pk])) {\n            $where = [$pk => $this->data[$pk]];\n        } elseif (!empty($this->updateWhere)) {\n            $where = $this->updateWhere;\n        } else {\n            $where = null;\n        }\n\n        // 删除当前模型数据\n        $result = $this->getQuery()->where($where)->delete();\n\n        // 关联删除\n        if (!empty($this->relationWrite)) {\n            foreach ($this->relationWrite as $key => $name) {\n                $name  = is_numeric($key) ? $name : $key;\n                $model = $this->getAttr($name);\n                if ($model instanceof Model) {\n                    $model->delete();\n                }\n            }\n        }\n\n        $this->trigger('after_delete', $this);\n        // 清空原始数据\n        $this->origin = [];\n\n        return $result;\n    }\n\n    /**\n     * 设置自动完成的字段（ 规则通过修改器定义）\n     * @access public\n     * @param array $fields 需要自动完成的字段\n     * @return $this\n     */\n    public function auto($fields)\n    {\n        $this->auto = $fields;\n        return $this;\n    }\n\n    /**\n     * 设置字段验证\n     * @access public\n     * @param array|string|bool $rule  验证规则 true表示自动读取验证器类\n     * @param array             $msg   提示信息\n     * @param bool              $batch 批量验证\n     * @return $this\n     */\n    public function validate($rule = true, $msg = [], $batch = false)\n    {\n        if (is_array($rule)) {\n            $this->validate = [\n                'rule' => $rule,\n                'msg'  => $msg,\n            ];\n        } else {\n            $this->validate = true === $rule ? $this->name : $rule;\n        }\n        $this->batchValidate = $batch;\n        return $this;\n    }\n\n    /**\n     * 设置验证失败后是否抛出异常\n     * @access public\n     * @param bool $fail 是否抛出异常\n     * @return $this\n     */\n    public function validateFailException($fail = true)\n    {\n        $this->failException = $fail;\n        return $this;\n    }\n\n    /**\n     * 自动验证数据\n     * @access protected\n     * @param array $data  验证数据\n     * @param mixed $rule  验证规则\n     * @param bool  $batch 批量验证\n     * @return bool\n     */\n    protected function validateData($data, $rule = null, $batch = null)\n    {\n        $info = is_null($rule) ? $this->validate : $rule;\n\n        if (!empty($info)) {\n            if (is_array($info)) {\n                $validate = Loader::validate();\n                $validate->rule($info['rule']);\n                $validate->message($info['msg']);\n            } else {\n                $name = is_string($info) ? $info : $this->name;\n                if (strpos($name, '.')) {\n                    list($name, $scene) = explode('.', $name);\n                }\n                $validate = Loader::validate($name);\n                if (!empty($scene)) {\n                    $validate->scene($scene);\n                }\n            }\n            $batch = is_null($batch) ? $this->batchValidate : $batch;\n\n            if (!$validate->batch($batch)->check($data)) {\n                $this->error = $validate->getError();\n                if ($this->failException) {\n                    throw new ValidateException($this->error);\n                } else {\n                    return false;\n                }\n            }\n            $this->validate = null;\n        }\n        return true;\n    }\n\n    /**\n     * 返回模型的错误信息\n     * @access public\n     * @return string|array\n     */\n    public function getError()\n    {\n        return $this->error;\n    }\n\n    /**\n     * 注册回调方法\n     * @access public\n     * @param string   $event    事件名\n     * @param callable $callback 回调方法\n     * @param bool     $override 是否覆盖\n     * @return void\n     */\n    public static function event($event, $callback, $override = false)\n    {\n        $class = get_called_class();\n        if ($override) {\n            self::$event[$class][$event] = [];\n        }\n        self::$event[$class][$event][] = $callback;\n    }\n\n    /**\n     * 触发事件\n     * @access protected\n     * @param string $event  事件名\n     * @param mixed  $params 传入参数（引用）\n     * @return bool\n     */\n    protected function trigger($event, &$params)\n    {\n        if (isset(self::$event[$this->class][$event])) {\n            foreach (self::$event[$this->class][$event] as $callback) {\n                if (is_callable($callback)) {\n                    $result = call_user_func_array($callback, [ & $params]);\n                    if (false === $result) {\n                        return false;\n                    }\n                }\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 写入数据\n     * @access public\n     * @param array      $data  数据数组\n     * @param array|true $field 允许字段\n     * @return $this\n     */\n    public static function create($data = [], $field = null)\n    {\n        $model = new static();\n        if (!empty($field)) {\n            $model->allowField($field);\n        }\n        $model->isUpdate(false)->save($data, []);\n        return $model;\n    }\n\n    /**\n     * 更新数据\n     * @access public\n     * @param array      $data  数据数组\n     * @param array      $where 更新条件\n     * @param array|true $field 允许字段\n     * @return $this\n     */\n    public static function update($data = [], $where = [], $field = null)\n    {\n        $model = new static();\n        if (!empty($field)) {\n            $model->allowField($field);\n        }\n        $result = $model->isUpdate(true)->save($data, $where);\n        return $model;\n    }\n\n    /**\n     * 查找单条记录\n     * @access public\n     * @param mixed        $data  主键值或者查询条件（闭包）\n     * @param array|string $with  关联预查询\n     * @param bool         $cache 是否缓存\n     * @return static|null\n     * @throws exception\\DbException\n     */\n    public static function get($data, $with = [], $cache = false)\n    {\n        if (is_null($data)) {\n            return;\n        }\n\n        if (true === $with || is_int($with)) {\n            $cache = $with;\n            $with  = [];\n        }\n        $query = static::parseQuery($data, $with, $cache);\n        return $query->find($data);\n    }\n\n    /**\n     * 查找所有记录\n     * @access public\n     * @param mixed        $data  主键列表或者查询条件（闭包）\n     * @param array|string $with  关联预查询\n     * @param bool         $cache 是否缓存\n     * @return static[]|false\n     * @throws exception\\DbException\n     */\n    public static function all($data = null, $with = [], $cache = false)\n    {\n        if (true === $with || is_int($with)) {\n            $cache = $with;\n            $with  = [];\n        }\n        $query = static::parseQuery($data, $with, $cache);\n        return $query->select($data);\n    }\n\n    /**\n     * 分析查询表达式\n     * @access public\n     * @param mixed  $data  主键列表或者查询条件（闭包）\n     * @param string $with  关联预查询\n     * @param bool   $cache 是否缓存\n     * @return Query\n     */\n    protected static function parseQuery(&$data, $with, $cache)\n    {\n        $result = self::with($with)->cache($cache);\n        if (is_array($data) && key($data) !== 0) {\n            $result = $result->where($data);\n            $data   = null;\n        } elseif ($data instanceof \\Closure) {\n            call_user_func_array($data, [ & $result]);\n            $data = null;\n        } elseif ($data instanceof Query) {\n            $result = $data->with($with)->cache($cache);\n            $data   = null;\n        }\n        return $result;\n    }\n\n    /**\n     * 删除记录\n     * @access public\n     * @param mixed $data 主键列表 支持闭包查询条件\n     * @return integer 成功删除的记录数\n     */\n    public static function destroy($data)\n    {\n        $model = new static();\n        $query = $model->db();\n        if (is_array($data) && key($data) !== 0) {\n            $query->where($data);\n            $data = null;\n        } elseif ($data instanceof \\Closure) {\n            call_user_func_array($data, [ & $query]);\n            $data = null;\n        } elseif (empty($data) && 0 !== $data) {\n            return 0;\n        }\n        $resultSet = $query->select($data);\n        $count     = 0;\n        if ($resultSet) {\n            foreach ($resultSet as $data) {\n                $result = $data->delete();\n                $count += $result;\n            }\n        }\n        return $count;\n    }\n\n    /**\n     * 命名范围\n     * @access public\n     * @param string|array|\\Closure $name 命名范围名称 逗号分隔\n     * @internal  mixed                 ...$params 参数调用\n     * @return Query\n     */\n    public static function scope($name)\n    {\n        $model  = new static();\n        $query  = $model->db();\n        $params = func_get_args();\n        array_shift($params);\n        array_unshift($params, $query);\n        if ($name instanceof \\Closure) {\n            call_user_func_array($name, $params);\n        } elseif (is_string($name)) {\n            $name = explode(',', $name);\n        }\n        if (is_array($name)) {\n            foreach ($name as $scope) {\n                $method = 'scope' . trim($scope);\n                if (method_exists($model, $method)) {\n                    call_user_func_array([$model, $method], $params);\n                }\n            }\n        }\n        return $query;\n    }\n\n    /**\n     * 设置是否使用全局查询范围\n     * @param bool $use 是否启用全局查询范围\n     * @access public\n     * @return Model\n     */\n    public static function useGlobalScope($use)\n    {\n        $model = new static();\n        return $model->db($use);\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param string  $relation 关联方法名\n     * @param mixed   $operator 比较操作符\n     * @param integer $count    个数\n     * @param string  $id       关联表的统计字段\n     * @return Relation|Query\n     */\n    public static function has($relation, $operator = '>=', $count = 1, $id = '*')\n    {\n        $relation = (new static())->$relation();\n        if (is_array($operator) || $operator instanceof \\Closure) {\n            return $relation->hasWhere($operator);\n        }\n        return $relation->has($operator, $count, $id);\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param string $relation 关联方法名\n     * @param mixed  $where    查询条件（数组或者闭包）\n     * @return Relation|Query\n     */\n    public static function hasWhere($relation, $where = [])\n    {\n        return (new static())->$relation()->hasWhere($where);\n    }\n\n    /**\n     * 解析模型的完整命名空间\n     * @access public\n     * @param string $model 模型名（或者完整类名）\n     * @return string\n     */\n    protected function parseModel($model)\n    {\n        if (false === strpos($model, '\\\\')) {\n            $path = explode('\\\\', get_called_class());\n            array_pop($path);\n            array_push($path, Loader::parseName($model, 1));\n            $model = implode('\\\\', $path);\n        }\n        return $model;\n    }\n\n    /**\n     * 查询当前模型的关联数据\n     * @access public\n     * @param string|array $relations 关联名\n     * @return $this\n     */\n    public function relationQuery($relations)\n    {\n        if (is_string($relations)) {\n            $relations = explode(',', $relations);\n        }\n\n        foreach ($relations as $key => $relation) {\n            $subRelation = '';\n            $closure     = null;\n            if ($relation instanceof \\Closure) {\n                // 支持闭包查询过滤关联条件\n                $closure  = $relation;\n                $relation = $key;\n            }\n            if (is_array($relation)) {\n                $subRelation = $relation;\n                $relation    = $key;\n            } elseif (strpos($relation, '.')) {\n                list($relation, $subRelation) = explode('.', $relation, 2);\n            }\n            $method                = Loader::parseName($relation, 1, false);\n            $this->data[$relation] = $this->$method()->getRelation($subRelation, $closure);\n        }\n        return $this;\n    }\n\n    /**\n     * 预载入关联查询 返回数据集\n     * @access public\n     * @param array  $resultSet 数据集\n     * @param string $relation  关联名\n     * @return array\n     */\n    public function eagerlyResultSet(&$resultSet, $relation)\n    {\n        $relations = is_string($relation) ? explode(',', $relation) : $relation;\n        foreach ($relations as $key => $relation) {\n            $subRelation = '';\n            $closure     = false;\n            if ($relation instanceof \\Closure) {\n                $closure  = $relation;\n                $relation = $key;\n            }\n            if (is_array($relation)) {\n                $subRelation = $relation;\n                $relation    = $key;\n            } elseif (strpos($relation, '.')) {\n                list($relation, $subRelation) = explode('.', $relation, 2);\n            }\n            $relation = Loader::parseName($relation, 1, false);\n            $this->$relation()->eagerlyResultSet($resultSet, $relation, $subRelation, $closure);\n        }\n    }\n\n    /**\n     * 预载入关联查询 返回模型对象\n     * @access public\n     * @param Model  $result   数据对象\n     * @param string $relation 关联名\n     * @return Model\n     */\n    public function eagerlyResult(&$result, $relation)\n    {\n        $relations = is_string($relation) ? explode(',', $relation) : $relation;\n\n        foreach ($relations as $key => $relation) {\n            $subRelation = '';\n            $closure     = false;\n            if ($relation instanceof \\Closure) {\n                $closure  = $relation;\n                $relation = $key;\n            }\n            if (is_array($relation)) {\n                $subRelation = $relation;\n                $relation    = $key;\n            } elseif (strpos($relation, '.')) {\n                list($relation, $subRelation) = explode('.', $relation, 2);\n            }\n            $relation = Loader::parseName($relation, 1, false);\n            $this->$relation()->eagerlyResult($result, $relation, $subRelation, $closure);\n        }\n    }\n\n    /**\n     * 关联统计\n     * @access public\n     * @param Model        $result   数据对象\n     * @param string|array $relation 关联名\n     * @return void\n     */\n    public function relationCount(&$result, $relation)\n    {\n        $relations = is_string($relation) ? explode(',', $relation) : $relation;\n\n        foreach ($relations as $key => $relation) {\n            $closure = false;\n            if ($relation instanceof \\Closure) {\n                $closure  = $relation;\n                $relation = $key;\n            } elseif (is_string($key)) {\n                $name     = $relation;\n                $relation = $key;\n            }\n            $relation = Loader::parseName($relation, 1, false);\n            $count    = $this->$relation()->relationCount($result, $closure);\n            if (!isset($name)) {\n                $name = Loader::parseName($relation) . '_count';\n            }\n            $result->setAttr($name, $count);\n        }\n    }\n\n    /**\n     * 获取模型的默认外键名\n     * @access public\n     * @param string $name 模型名\n     * @return string\n     */\n    protected function getForeignKey($name)\n    {\n        if (strpos($name, '\\\\')) {\n            $name = basename(str_replace('\\\\', '/', $name));\n        }\n        return Loader::parseName($name) . '_id';\n    }\n\n    /**\n     * HAS ONE 关联定义\n     * @access public\n     * @param string $model      模型名\n     * @param string $foreignKey 关联外键\n     * @param string $localKey   关联主键\n     * @param array  $alias      别名定义（已经废弃）\n     * @param string $joinType   JOIN类型\n     * @return HasOne\n     */\n    public function hasOne($model, $foreignKey = '', $localKey = '', $alias = [], $joinType = 'INNER')\n    {\n        // 记录当前关联信息\n        $model      = $this->parseModel($model);\n        $localKey   = $localKey ?: $this->getPk();\n        $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);\n        return new HasOne($this, $model, $foreignKey, $localKey, $joinType);\n    }\n\n    /**\n     * BELONGS TO 关联定义\n     * @access public\n     * @param string $model      模型名\n     * @param string $foreignKey 关联外键\n     * @param string $localKey   关联主键\n     * @param array  $alias      别名定义（已经废弃）\n     * @param string $joinType   JOIN类型\n     * @return BelongsTo\n     */\n    public function belongsTo($model, $foreignKey = '', $localKey = '', $alias = [], $joinType = 'INNER')\n    {\n        // 记录当前关联信息\n        $model      = $this->parseModel($model);\n        $foreignKey = $foreignKey ?: $this->getForeignKey($model);\n        $localKey   = $localKey ?: (new $model)->getPk();\n        $trace      = debug_backtrace(false, 2);\n        $relation   = Loader::parseName($trace[1]['function']);\n        return new BelongsTo($this, $model, $foreignKey, $localKey, $joinType, $relation);\n    }\n\n    /**\n     * HAS MANY 关联定义\n     * @access public\n     * @param string $model      模型名\n     * @param string $foreignKey 关联外键\n     * @param string $localKey   关联主键\n     * @return HasMany\n     */\n    public function hasMany($model, $foreignKey = '', $localKey = '')\n    {\n        // 记录当前关联信息\n        $model      = $this->parseModel($model);\n        $localKey   = $localKey ?: $this->getPk();\n        $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);\n        return new HasMany($this, $model, $foreignKey, $localKey);\n    }\n\n    /**\n     * HAS MANY 远程关联定义\n     * @access public\n     * @param string $model      模型名\n     * @param string $through    中间模型名\n     * @param string $foreignKey 关联外键\n     * @param string $throughKey 关联外键\n     * @param string $localKey   关联主键\n     * @return HasManyThrough\n     */\n    public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = '', $localKey = '')\n    {\n        // 记录当前关联信息\n        $model      = $this->parseModel($model);\n        $through    = $this->parseModel($through);\n        $localKey   = $localKey ?: $this->getPk();\n        $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);\n        $throughKey = $throughKey ?: $this->getForeignKey($through);\n        return new HasManyThrough($this, $model, $through, $foreignKey, $throughKey, $localKey);\n    }\n\n    /**\n     * BELONGS TO MANY 关联定义\n     * @access public\n     * @param string $model      模型名\n     * @param string $table      中间表名\n     * @param string $foreignKey 关联外键\n     * @param string $localKey   当前模型关联键\n     * @return BelongsToMany\n     */\n    public function belongsToMany($model, $table = '', $foreignKey = '', $localKey = '')\n    {\n        // 记录当前关联信息\n        $model      = $this->parseModel($model);\n        $name       = Loader::parseName(basename(str_replace('\\\\', '/', $model)));\n        $table      = $table ?: Loader::parseName($this->name) . '_' . $name;\n        $foreignKey = $foreignKey ?: $name . '_id';\n        $localKey   = $localKey ?: $this->getForeignKey($this->name);\n        return new BelongsToMany($this, $model, $table, $foreignKey, $localKey);\n    }\n\n    /**\n     * MORPH  MANY 关联定义\n     * @access public\n     * @param string       $model 模型名\n     * @param string|array $morph 多态字段信息\n     * @param string       $type  多态类型\n     * @return MorphMany\n     */\n    public function morphMany($model, $morph = null, $type = '')\n    {\n        // 记录当前关联信息\n        $model = $this->parseModel($model);\n        if (is_null($morph)) {\n            $trace = debug_backtrace(false, 2);\n            $morph = Loader::parseName($trace[1]['function']);\n        }\n        $type = $type ?: Loader::parseName($this->name);\n        if (is_array($morph)) {\n            list($morphType, $foreignKey) = $morph;\n        } else {\n            $morphType  = $morph . '_type';\n            $foreignKey = $morph . '_id';\n        }\n        return new MorphMany($this, $model, $foreignKey, $morphType, $type);\n    }\n\n    /**\n     * MORPH  One 关联定义\n     * @access public\n     * @param string       $model 模型名\n     * @param string|array $morph 多态字段信息\n     * @param string       $type  多态类型\n     * @return MorphOne\n     */\n    public function morphOne($model, $morph = null, $type = '')\n    {\n        // 记录当前关联信息\n        $model = $this->parseModel($model);\n        if (is_null($morph)) {\n            $trace = debug_backtrace(false, 2);\n            $morph = Loader::parseName($trace[1]['function']);\n        }\n        $type = $type ?: Loader::parseName($this->name);\n        if (is_array($morph)) {\n            list($morphType, $foreignKey) = $morph;\n        } else {\n            $morphType  = $morph . '_type';\n            $foreignKey = $morph . '_id';\n        }\n        return new MorphOne($this, $model, $foreignKey, $morphType, $type);\n    }\n\n    /**\n     * MORPH TO 关联定义\n     * @access public\n     * @param string|array $morph 多态字段信息\n     * @param array        $alias 多态别名定义\n     * @return MorphTo\n     */\n    public function morphTo($morph = null, $alias = [])\n    {\n        $trace    = debug_backtrace(false, 2);\n        $relation = Loader::parseName($trace[1]['function']);\n\n        if (is_null($morph)) {\n            $morph = $relation;\n        }\n        // 记录当前关联信息\n        if (is_array($morph)) {\n            list($morphType, $foreignKey) = $morph;\n        } else {\n            $morphType  = $morph . '_type';\n            $foreignKey = $morph . '_id';\n        }\n        return new MorphTo($this, $morphType, $foreignKey, $alias, $relation);\n    }\n\n    public function __call($method, $args)\n    {\n        $query = $this->db(true, false);\n\n        if (method_exists($this, 'scope' . $method)) {\n            // 动态调用命名范围\n            $method = 'scope' . $method;\n            array_unshift($args, $query);\n            call_user_func_array([$this, $method], $args);\n            return $this;\n        } else {\n            return call_user_func_array([$query, $method], $args);\n        }\n    }\n\n    public static function __callStatic($method, $args)\n    {\n        $model = new static();\n        $query = $model->db();\n\n        if (method_exists($model, 'scope' . $method)) {\n            // 动态调用命名范围\n            $method = 'scope' . $method;\n            array_unshift($args, $query);\n\n            call_user_func_array([$model, $method], $args);\n            return $query;\n        } else {\n            return call_user_func_array([$query, $method], $args);\n        }\n    }\n\n    /**\n     * 修改器 设置数据对象的值\n     * @access public\n     * @param string $name  名称\n     * @param mixed  $value 值\n     * @return void\n     */\n    public function __set($name, $value)\n    {\n        $this->setAttr($name, $value);\n    }\n\n    /**\n     * 获取器 获取数据对象的值\n     * @access public\n     * @param string $name 名称\n     * @return mixed\n     */\n    public function __get($name)\n    {\n        return $this->getAttr($name);\n    }\n\n    /**\n     * 检测数据对象的值\n     * @access public\n     * @param string $name 名称\n     * @return boolean\n     */\n    public function __isset($name)\n    {\n        try {\n            if (array_key_exists($name, $this->data) || array_key_exists($name, $this->relation)) {\n                return true;\n            } else {\n                $this->getAttr($name);\n                return true;\n            }\n        } catch (InvalidArgumentException $e) {\n            return false;\n        }\n\n    }\n\n    /**\n     * 销毁数据对象的值\n     * @access public\n     * @param string $name 名称\n     * @return void\n     */\n    public function __unset($name)\n    {\n        unset($this->data[$name], $this->relation[$name]);\n    }\n\n    public function __toString()\n    {\n        return $this->toJson();\n    }\n\n    // JsonSerializable\n    public function jsonSerialize()\n    {\n        return $this->toArray();\n    }\n\n    // ArrayAccess\n    public function offsetSet($name, $value)\n    {\n        $this->setAttr($name, $value);\n    }\n\n    public function offsetExists($name)\n    {\n        return $this->__isset($name);\n    }\n\n    public function offsetUnset($name)\n    {\n        $this->__unset($name);\n    }\n\n    public function offsetGet($name)\n    {\n        return $this->getAttr($name);\n    }\n\n    /**\n     * 解序列化后处理\n     */\n    public function __wakeup()\n    {\n        $this->initialize();\n    }\n\n    /**\n     * 模型事件快捷方法\n     * @param      $callback\n     * @param bool $override\n     */\n    protected static function beforeInsert($callback, $override = false)\n    {\n        self::event('before_insert', $callback, $override);\n    }\n\n    protected static function afterInsert($callback, $override = false)\n    {\n        self::event('after_insert', $callback, $override);\n    }\n\n    protected static function beforeUpdate($callback, $override = false)\n    {\n        self::event('before_update', $callback, $override);\n    }\n\n    protected static function afterUpdate($callback, $override = false)\n    {\n        self::event('after_update', $callback, $override);\n    }\n\n    protected static function beforeWrite($callback, $override = false)\n    {\n        self::event('before_write', $callback, $override);\n    }\n\n    protected static function afterWrite($callback, $override = false)\n    {\n        self::event('after_write', $callback, $override);\n    }\n\n    protected static function beforeDelete($callback, $override = false)\n    {\n        self::event('before_delete', $callback, $override);\n    }\n\n    protected static function afterDelete($callback, $override = false)\n    {\n        self::event('after_delete', $callback, $override);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/Paginator.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: zhangyajun <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse ArrayAccess;\nuse ArrayIterator;\nuse Countable;\nuse IteratorAggregate;\nuse JsonSerializable;\nuse Traversable;\n\nabstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable\n{\n    /** @var bool 是否为简洁模式 */\n    protected $simple = false;\n\n    /** @var Collection 数据集 */\n    protected $items;\n\n    /** @var integer 当前页 */\n    protected $currentPage;\n\n    /** @var  integer 最后一页 */\n    protected $lastPage;\n\n    /** @var integer|null 数据总数 */\n    protected $total;\n\n    /** @var  integer 每页的数量 */\n    protected $listRows;\n\n    /** @var bool 是否有下一页 */\n    protected $hasMore;\n\n    /** @var array 一些配置 */\n    protected $options = [\n        'var_page' => 'page',\n        'path'     => '/',\n        'query'    => [],\n        'fragment' => '',\n    ];\n\n    public function __construct($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])\n    {\n        $this->options = array_merge($this->options, $options);\n\n        $this->options['path'] = '/' != $this->options['path'] ? rtrim($this->options['path'], '/') : $this->options['path'];\n\n        $this->simple   = $simple;\n        $this->listRows = $listRows;\n\n        if (!$items instanceof Collection) {\n            $items = Collection::make($items);\n        }\n\n        if ($simple) {\n            $this->currentPage = $this->setCurrentPage($currentPage);\n            $this->hasMore     = count($items) > ($this->listRows);\n            $items             = $items->slice(0, $this->listRows);\n        } else {\n            $this->total       = $total;\n            $this->lastPage    = (int) ceil($total / $listRows);\n            $this->currentPage = $this->setCurrentPage($currentPage);\n            $this->hasMore     = $this->currentPage < $this->lastPage;\n        }\n        $this->items = $items;\n    }\n\n    /**\n     * @param       $items\n     * @param       $listRows\n     * @param null  $currentPage\n     * @param bool  $simple\n     * @param null  $total\n     * @param array $options\n     * @return Paginator\n     */\n    public static function make($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = [])\n    {\n        return new static($items, $listRows, $currentPage, $total, $simple, $options);\n    }\n\n    protected function setCurrentPage($currentPage)\n    {\n        if (!$this->simple && $currentPage > $this->lastPage) {\n            return $this->lastPage > 0 ? $this->lastPage : 1;\n        }\n\n        return $currentPage;\n    }\n\n    /**\n     * 获取页码对应的链接\n     *\n     * @param $page\n     * @return string\n     */\n    protected function url($page)\n    {\n        if ($page <= 0) {\n            $page = 1;\n        }\n\n        if (strpos($this->options['path'], '[PAGE]') === false) {\n            $parameters = [$this->options['var_page'] => $page];\n            $path       = $this->options['path'];\n        } else {\n            $parameters = [];\n            $path       = str_replace('[PAGE]', $page, $this->options['path']);\n        }\n        if (count($this->options['query']) > 0) {\n            $parameters = array_merge($this->options['query'], $parameters);\n        }\n        $url = $path;\n        if (!empty($parameters)) {\n            $url .= '?' . urldecode(http_build_query($parameters, null, '&'));\n        }\n        return $url . $this->buildFragment();\n    }\n\n    /**\n     * 自动获取当前页码\n     * @param string $varPage\n     * @param int    $default\n     * @return int\n     */\n    public static function getCurrentPage($varPage = 'page', $default = 1)\n    {\n        $page = Request::instance()->request($varPage);\n\n        if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) {\n            return $page;\n        }\n\n        return $default;\n    }\n\n    /**\n     * 自动获取当前的path\n     * @return string\n     */\n    public static function getCurrentPath()\n    {\n        return Request::instance()->baseUrl();\n    }\n\n    public function total()\n    {\n        if ($this->simple) {\n            throw new \\DomainException('not support total');\n        }\n        return $this->total;\n    }\n\n    public function listRows()\n    {\n        return $this->listRows;\n    }\n\n    public function currentPage()\n    {\n        return $this->currentPage;\n    }\n\n    public function lastPage()\n    {\n        if ($this->simple) {\n            throw new \\DomainException('not support last');\n        }\n        return $this->lastPage;\n    }\n\n    /**\n     * 数据是否足够分页\n     * @return boolean\n     */\n    public function hasPages()\n    {\n        return !(1 == $this->currentPage && !$this->hasMore);\n    }\n\n    /**\n     * 创建一组分页链接\n     *\n     * @param  int $start\n     * @param  int $end\n     * @return array\n     */\n    public function getUrlRange($start, $end)\n    {\n        $urls = [];\n\n        for ($page = $start; $page <= $end; $page++) {\n            $urls[$page] = $this->url($page);\n        }\n\n        return $urls;\n    }\n\n    /**\n     * 设置URL锚点\n     *\n     * @param  string|null $fragment\n     * @return $this\n     */\n    public function fragment($fragment)\n    {\n        $this->options['fragment'] = $fragment;\n        return $this;\n    }\n\n    /**\n     * 添加URL参数\n     *\n     * @param  array|string $key\n     * @param  string|null  $value\n     * @return $this\n     */\n    public function appends($key, $value = null)\n    {\n        if (!is_array($key)) {\n            $queries = [$key => $value];\n        } else {\n            $queries = $key;\n        }\n\n        foreach ($queries as $k => $v) {\n            if ($k !== $this->options['var_page']) {\n                $this->options['query'][$k] = $v;\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * 构造锚点字符串\n     *\n     * @return string\n     */\n    protected function buildFragment()\n    {\n        return $this->options['fragment'] ? '#' . $this->options['fragment'] : '';\n    }\n\n    /**\n     * 渲染分页html\n     * @return mixed\n     */\n    abstract public function render();\n\n    public function items()\n    {\n        return $this->items->all();\n    }\n\n    public function getCollection()\n    {\n        return $this->items;\n    }\n\n    public function isEmpty()\n    {\n        return $this->items->isEmpty();\n    }\n\n    /**\n     * 给每个元素执行个回调\n     *\n     * @param  callable $callback\n     * @return $this\n     */\n    public function each(callable $callback)\n    {\n        foreach ($this->items as $key => $item) {\n            if ($callback($item, $key) === false) {\n                break;\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Retrieve an external iterator\n     * @return Traversable An instance of an object implementing <b>Iterator</b> or\n     * <b>Traversable</b>\n     */\n    public function getIterator()\n    {\n        return new ArrayIterator($this->items->all());\n    }\n\n    /**\n     * Whether a offset exists\n     * @param mixed $offset\n     * @return bool\n     */\n    public function offsetExists($offset)\n    {\n        return $this->items->offsetExists($offset);\n    }\n\n    /**\n     * Offset to retrieve\n     * @param mixed $offset\n     * @return mixed\n     */\n    public function offsetGet($offset)\n    {\n        return $this->items->offsetGet($offset);\n    }\n\n    /**\n     * Offset to set\n     * @param mixed $offset\n     * @param mixed $value\n     */\n    public function offsetSet($offset, $value)\n    {\n        $this->items->offsetSet($offset, $value);\n    }\n\n    /**\n     * Offset to unset\n     * @param mixed $offset\n     * @return void\n     * @since 5.0.0\n     */\n    public function offsetUnset($offset)\n    {\n        $this->items->offsetUnset($offset);\n    }\n\n    /**\n     * Count elements of an object\n     */\n    public function count()\n    {\n        return $this->items->count();\n    }\n\n    public function __toString()\n    {\n        return (string) $this->render();\n    }\n\n    public function toArray()\n    {\n        try {\n            $total = $this->total();\n        } catch (\\DomainException $e) {\n            $total = null;\n        }\n\n        return [\n            'total'        => $total,\n            'per_page'     => $this->listRows(),\n            'current_page' => $this->currentPage(),\n            'last_page'    => $this->lastPage,\n            'data'         => $this->items->toArray(),\n        ];\n    }\n\n    /**\n     * Specify data which should be serialized to JSON\n     */\n    public function jsonSerialize()\n    {\n        return $this->toArray();\n    }\n\n    public function __call($name, $arguments)\n    {\n        return call_user_func_array([$this->getCollection(), $name], $arguments);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/Process.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\process\\exception\\Failed as ProcessFailedException;\nuse think\\process\\exception\\Timeout as ProcessTimeoutException;\nuse think\\process\\pipes\\Pipes;\nuse think\\process\\pipes\\Unix as UnixPipes;\nuse think\\process\\pipes\\Windows as WindowsPipes;\nuse think\\process\\Utils;\n\nclass Process\n{\n\n    const ERR = 'err';\n    const OUT = 'out';\n\n    const STATUS_READY      = 'ready';\n    const STATUS_STARTED    = 'started';\n    const STATUS_TERMINATED = 'terminated';\n\n    const STDIN  = 0;\n    const STDOUT = 1;\n    const STDERR = 2;\n\n    const TIMEOUT_PRECISION = 0.2;\n\n    private $callback;\n    private $commandline;\n    private $cwd;\n    private $env;\n    private $input;\n    private $starttime;\n    private $lastOutputTime;\n    private $timeout;\n    private $idleTimeout;\n    private $options;\n    private $exitcode;\n    private $fallbackExitcode;\n    private $processInformation;\n    private $outputDisabled = false;\n    private $stdout;\n    private $stderr;\n    private $enhanceWindowsCompatibility = true;\n    private $enhanceSigchildCompatibility;\n    private $process;\n    private $status                       = self::STATUS_READY;\n    private $incrementalOutputOffset      = 0;\n    private $incrementalErrorOutputOffset = 0;\n    private $tty;\n    private $pty;\n\n    private $useFileHandles = false;\n\n    /** @var Pipes */\n    private $processPipes;\n\n    private $latestSignal;\n\n    private static $sigchild;\n\n    /**\n     * @var array\n     */\n    public static $exitCodes = [\n        0   => 'OK',\n        1   => 'General error',\n        2   => 'Misuse of shell builtins',\n        126 => 'Invoked command cannot execute',\n        127 => 'Command not found',\n        128 => 'Invalid exit argument',\n        // signals\n        129 => 'Hangup',\n        130 => 'Interrupt',\n        131 => 'Quit and dump core',\n        132 => 'Illegal instruction',\n        133 => 'Trace/breakpoint trap',\n        134 => 'Process aborted',\n        135 => 'Bus error: \"access to undefined portion of memory object\"',\n        136 => 'Floating point exception: \"erroneous arithmetic operation\"',\n        137 => 'Kill (terminate immediately)',\n        138 => 'User-defined 1',\n        139 => 'Segmentation violation',\n        140 => 'User-defined 2',\n        141 => 'Write to pipe with no one reading',\n        142 => 'Signal raised by alarm',\n        143 => 'Termination (request to terminate)',\n        // 144 - not defined\n        145 => 'Child process terminated, stopped (or continued*)',\n        146 => 'Continue if stopped',\n        147 => 'Stop executing temporarily',\n        148 => 'Terminal stop signal',\n        149 => 'Background process attempting to read from tty (\"in\")',\n        150 => 'Background process attempting to write to tty (\"out\")',\n        151 => 'Urgent data available on socket',\n        152 => 'CPU time limit exceeded',\n        153 => 'File size limit exceeded',\n        154 => 'Signal raised by timer counting virtual time: \"virtual timer expired\"',\n        155 => 'Profiling timer expired',\n        // 156 - not defined\n        157 => 'Pollable event',\n        // 158 - not defined\n        159 => 'Bad syscall',\n    ];\n\n    /**\n     * 构造方法\n     * @param string         $commandline 指令\n     * @param string|null    $cwd         工作目录\n     * @param array|null     $env         环境变量\n     * @param string|null    $input       输入\n     * @param int|float|null $timeout     超时时间\n     * @param array          $options     proc_open的选项\n     * @throws \\RuntimeException\n     * @api\n     */\n    public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = [])\n    {\n        if (!function_exists('proc_open')) {\n            throw new \\RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.');\n        }\n\n        $this->commandline = $commandline;\n        $this->cwd         = $cwd;\n\n        if (null === $this->cwd && (defined('ZEND_THREAD_SAFE') || '\\\\' === DS)) {\n            $this->cwd = getcwd();\n        }\n        if (null !== $env) {\n            $this->setEnv($env);\n        }\n\n        $this->input = $input;\n        $this->setTimeout($timeout);\n        $this->useFileHandles               = '\\\\' === DS;\n        $this->pty                          = false;\n        $this->enhanceWindowsCompatibility  = true;\n        $this->enhanceSigchildCompatibility = '\\\\' !== DS && $this->isSigchildEnabled();\n        $this->options                      = array_replace([\n            'suppress_errors' => true,\n            'binary_pipes'    => true,\n        ], $options);\n    }\n\n    public function __destruct()\n    {\n        $this->stop();\n    }\n\n    public function __clone()\n    {\n        $this->resetProcessData();\n    }\n\n    /**\n     * 运行指令\n     * @param callback|null $callback\n     * @return int\n     */\n    public function run($callback = null)\n    {\n        $this->start($callback);\n\n        return $this->wait();\n    }\n\n    /**\n     * 运行指令\n     * @param callable|null $callback\n     * @return self\n     * @throws \\RuntimeException\n     * @throws ProcessFailedException\n     */\n    public function mustRun($callback = null)\n    {\n        if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) {\n            throw new \\RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');\n        }\n\n        if (0 !== $this->run($callback)) {\n            throw new ProcessFailedException($this);\n        }\n\n        return $this;\n    }\n\n    /**\n     * 启动进程并写到 STDIN 输入后返回。\n     * @param callable|null $callback\n     * @throws \\RuntimeException\n     * @throws \\RuntimeException\n     * @throws \\LogicException\n     */\n    public function start($callback = null)\n    {\n        if ($this->isRunning()) {\n            throw new \\RuntimeException('Process is already running');\n        }\n        if ($this->outputDisabled && null !== $callback) {\n            throw new \\LogicException('Output has been disabled, enable it to allow the use of a callback.');\n        }\n\n        $this->resetProcessData();\n        $this->starttime = $this->lastOutputTime = microtime(true);\n        $this->callback  = $this->buildCallback($callback);\n        $descriptors     = $this->getDescriptors();\n\n        $commandline = $this->commandline;\n\n        if ('\\\\' === DS && $this->enhanceWindowsCompatibility) {\n            $commandline = 'cmd /V:ON /E:ON /C \"(' . $commandline . ')';\n            foreach ($this->processPipes->getFiles() as $offset => $filename) {\n                $commandline .= ' ' . $offset . '>' . Utils::escapeArgument($filename);\n            }\n            $commandline .= '\"';\n\n            if (!isset($this->options['bypass_shell'])) {\n                $this->options['bypass_shell'] = true;\n            }\n        }\n\n        $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options);\n\n        if (!is_resource($this->process)) {\n            throw new \\RuntimeException('Unable to launch a new process.');\n        }\n        $this->status = self::STATUS_STARTED;\n\n        if ($this->tty) {\n            return;\n        }\n\n        $this->updateStatus(false);\n        $this->checkTimeout();\n    }\n\n    /**\n     * 重启进程\n     * @param callable|null $callback\n     * @return Process\n     * @throws \\RuntimeException\n     * @throws \\RuntimeException\n     */\n    public function restart($callback = null)\n    {\n        if ($this->isRunning()) {\n            throw new \\RuntimeException('Process is already running');\n        }\n\n        $process = clone $this;\n        $process->start($callback);\n\n        return $process;\n    }\n\n    /**\n     * 等待要终止的进程\n     * @param callable|null $callback\n     * @return int\n     */\n    public function wait($callback = null)\n    {\n        $this->requireProcessIsStarted(__FUNCTION__);\n\n        $this->updateStatus(false);\n        if (null !== $callback) {\n            $this->callback = $this->buildCallback($callback);\n        }\n\n        do {\n            $this->checkTimeout();\n            $running = '\\\\' === DS ? $this->isRunning() : $this->processPipes->areOpen();\n            $close   = '\\\\' !== DS || !$running;\n            $this->readPipes(true, $close);\n        } while ($running);\n\n        while ($this->isRunning()) {\n            usleep(1000);\n        }\n\n        if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {\n            throw new \\RuntimeException(sprintf('The process has been signaled with signal \"%s\".', $this->processInformation['termsig']));\n        }\n\n        return $this->exitcode;\n    }\n\n    /**\n     * 获取PID\n     * @return int|null\n     * @throws \\RuntimeException\n     */\n    public function getPid()\n    {\n        if ($this->isSigchildEnabled()) {\n            throw new \\RuntimeException('This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.');\n        }\n\n        $this->updateStatus(false);\n\n        return $this->isRunning() ? $this->processInformation['pid'] : null;\n    }\n\n    /**\n     * 将一个 POSIX 信号发送到进程中\n     * @param int $signal\n     * @return Process\n     */\n    public function signal($signal)\n    {\n        $this->doSignal($signal, true);\n\n        return $this;\n    }\n\n    /**\n     * 禁用从底层过程获取输出和错误输出。\n     * @return Process\n     */\n    public function disableOutput()\n    {\n        if ($this->isRunning()) {\n            throw new \\RuntimeException('Disabling output while the process is running is not possible.');\n        }\n        if (null !== $this->idleTimeout) {\n            throw new \\LogicException('Output can not be disabled while an idle timeout is set.');\n        }\n\n        $this->outputDisabled = true;\n\n        return $this;\n    }\n\n    /**\n     * 开启从底层过程获取输出和错误输出。\n     * @return Process\n     * @throws \\RuntimeException\n     */\n    public function enableOutput()\n    {\n        if ($this->isRunning()) {\n            throw new \\RuntimeException('Enabling output while the process is running is not possible.');\n        }\n\n        $this->outputDisabled = false;\n\n        return $this;\n    }\n\n    /**\n     * 输出是否禁用\n     * @return bool\n     */\n    public function isOutputDisabled()\n    {\n        return $this->outputDisabled;\n    }\n\n    /**\n     * 获取当前的输出管道\n     * @return string\n     * @throws \\LogicException\n     * @throws \\LogicException\n     * @api\n     */\n    public function getOutput()\n    {\n        if ($this->outputDisabled) {\n            throw new \\LogicException('Output has been disabled.');\n        }\n\n        $this->requireProcessIsStarted(__FUNCTION__);\n\n        $this->readPipes(false, '\\\\' === DS ? !$this->processInformation['running'] : true);\n\n        return $this->stdout;\n    }\n\n    /**\n     * 以增量方式返回的输出结果。\n     * @return string\n     */\n    public function getIncrementalOutput()\n    {\n        $this->requireProcessIsStarted(__FUNCTION__);\n\n        $data = $this->getOutput();\n\n        $latest = substr($data, $this->incrementalOutputOffset);\n\n        if (false === $latest) {\n            return '';\n        }\n\n        $this->incrementalOutputOffset = strlen($data);\n\n        return $latest;\n    }\n\n    /**\n     * 清空输出\n     * @return Process\n     */\n    public function clearOutput()\n    {\n        $this->stdout                  = '';\n        $this->incrementalOutputOffset = 0;\n\n        return $this;\n    }\n\n    /**\n     * 返回当前的错误输出的过程 (STDERR)。\n     * @return string\n     */\n    public function getErrorOutput()\n    {\n        if ($this->outputDisabled) {\n            throw new \\LogicException('Output has been disabled.');\n        }\n\n        $this->requireProcessIsStarted(__FUNCTION__);\n\n        $this->readPipes(false, '\\\\' === DS ? !$this->processInformation['running'] : true);\n\n        return $this->stderr;\n    }\n\n    /**\n     * 以增量方式返回 errorOutput\n     * @return string\n     */\n    public function getIncrementalErrorOutput()\n    {\n        $this->requireProcessIsStarted(__FUNCTION__);\n\n        $data = $this->getErrorOutput();\n\n        $latest = substr($data, $this->incrementalErrorOutputOffset);\n\n        if (false === $latest) {\n            return '';\n        }\n\n        $this->incrementalErrorOutputOffset = strlen($data);\n\n        return $latest;\n    }\n\n    /**\n     * 清空 errorOutput\n     * @return Process\n     */\n    public function clearErrorOutput()\n    {\n        $this->stderr                       = '';\n        $this->incrementalErrorOutputOffset = 0;\n\n        return $this;\n    }\n\n    /**\n     * 获取退出码\n     * @return null|int\n     */\n    public function getExitCode()\n    {\n        if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) {\n            throw new \\RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');\n        }\n\n        $this->updateStatus(false);\n\n        return $this->exitcode;\n    }\n\n    /**\n     * 获取退出文本\n     * @return null|string\n     */\n    public function getExitCodeText()\n    {\n        if (null === $exitcode = $this->getExitCode()) {\n            return;\n        }\n\n        return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error';\n    }\n\n    /**\n     * 检查是否成功\n     * @return bool\n     */\n    public function isSuccessful()\n    {\n        return 0 === $this->getExitCode();\n    }\n\n    /**\n     * 是否未捕获的信号已被终止子进程\n     * @return bool\n     */\n    public function hasBeenSignaled()\n    {\n        $this->requireProcessIsTerminated(__FUNCTION__);\n\n        if ($this->isSigchildEnabled()) {\n            throw new \\RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');\n        }\n\n        $this->updateStatus(false);\n\n        return $this->processInformation['signaled'];\n    }\n\n    /**\n     * 返回导致子进程终止其执行的数。\n     * @return int\n     */\n    public function getTermSignal()\n    {\n        $this->requireProcessIsTerminated(__FUNCTION__);\n\n        if ($this->isSigchildEnabled()) {\n            throw new \\RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');\n        }\n\n        $this->updateStatus(false);\n\n        return $this->processInformation['termsig'];\n    }\n\n    /**\n     * 检查子进程信号是否已停止\n     * @return bool\n     */\n    public function hasBeenStopped()\n    {\n        $this->requireProcessIsTerminated(__FUNCTION__);\n\n        $this->updateStatus(false);\n\n        return $this->processInformation['stopped'];\n    }\n\n    /**\n     * 返回导致子进程停止其执行的数。\n     * @return int\n     */\n    public function getStopSignal()\n    {\n        $this->requireProcessIsTerminated(__FUNCTION__);\n\n        $this->updateStatus(false);\n\n        return $this->processInformation['stopsig'];\n    }\n\n    /**\n     * 检查是否正在运行\n     * @return bool\n     */\n    public function isRunning()\n    {\n        if (self::STATUS_STARTED !== $this->status) {\n            return false;\n        }\n\n        $this->updateStatus(false);\n\n        return $this->processInformation['running'];\n    }\n\n    /**\n     * 检查是否已开始\n     * @return bool\n     */\n    public function isStarted()\n    {\n        return self::STATUS_READY != $this->status;\n    }\n\n    /**\n     * 检查是否已终止\n     * @return bool\n     */\n    public function isTerminated()\n    {\n        $this->updateStatus(false);\n\n        return self::STATUS_TERMINATED == $this->status;\n    }\n\n    /**\n     * 获取当前的状态\n     * @return string\n     */\n    public function getStatus()\n    {\n        $this->updateStatus(false);\n\n        return $this->status;\n    }\n\n    /**\n     * 终止进程\n     */\n    public function stop()\n    {\n        if ($this->isRunning()) {\n            if ('\\\\' === DS && !$this->isSigchildEnabled()) {\n                exec(sprintf('taskkill /F /T /PID %d 2>&1', $this->getPid()), $output, $exitCode);\n                if ($exitCode > 0) {\n                    throw new \\RuntimeException('Unable to kill the process');\n                }\n            } else {\n                $pids = preg_split('/\\s+/', `ps -o pid --no-heading --ppid {$this->getPid()}`);\n                foreach ($pids as $pid) {\n                    if (is_numeric($pid)) {\n                        posix_kill($pid, 9);\n                    }\n                }\n            }\n        }\n\n        $this->updateStatus(false);\n        if ($this->processInformation['running']) {\n            $this->close();\n        }\n\n        return $this->exitcode;\n    }\n\n    /**\n     * 添加一行输出\n     * @param string $line\n     */\n    public function addOutput($line)\n{\n        $this->lastOutputTime = microtime(true);\n        $this->stdout .= $line;\n    }\n\n    /**\n     * 添加一行错误输出\n     * @param string $line\n     */\n    public function addErrorOutput($line)\n{\n        $this->lastOutputTime = microtime(true);\n        $this->stderr .= $line;\n    }\n\n    /**\n     * 获取被执行的指令\n     * @return string\n     */\n    public function getCommandLine()\n{\n        return $this->commandline;\n    }\n\n    /**\n     * 设置指令\n     * @param string $commandline\n     * @return self\n     */\n    public function setCommandLine($commandline)\n{\n        $this->commandline = $commandline;\n\n        return $this;\n    }\n\n    /**\n     * 获取超时时间\n     * @return float|null\n     */\n    public function getTimeout()\n{\n        return $this->timeout;\n    }\n\n    /**\n     * 获取idle超时时间\n     * @return float|null\n     */\n    public function getIdleTimeout()\n{\n        return $this->idleTimeout;\n    }\n\n    /**\n     * 设置超时时间\n     * @param int|float|null $timeout\n     * @return self\n     */\n    public function setTimeout($timeout)\n{\n        $this->timeout = $this->validateTimeout($timeout);\n\n        return $this;\n    }\n\n    /**\n     * 设置idle超时时间\n     * @param int|float|null $timeout\n     * @return self\n     */\n    public function setIdleTimeout($timeout)\n{\n        if (null !== $timeout && $this->outputDisabled) {\n            throw new \\LogicException('Idle timeout can not be set while the output is disabled.');\n        }\n\n        $this->idleTimeout = $this->validateTimeout($timeout);\n\n        return $this;\n    }\n\n    /**\n     * 设置TTY\n     * @param bool $tty\n     * @return self\n     */\n    public function setTty($tty)\n{\n        if ('\\\\' === DS && $tty) {\n            throw new \\RuntimeException('TTY mode is not supported on Windows platform.');\n        }\n        if ($tty && (!file_exists('/dev/tty') || !is_readable('/dev/tty'))) {\n            throw new \\RuntimeException('TTY mode requires /dev/tty to be readable.');\n        }\n\n        $this->tty = (bool) $tty;\n\n        return $this;\n    }\n\n    /**\n     * 检查是否是tty模式\n     * @return bool\n     */\n    public function isTty()\n{\n        return $this->tty;\n    }\n\n    /**\n     * 设置pty模式\n     * @param bool $bool\n     * @return self\n     */\n    public function setPty($bool)\n{\n        $this->pty = (bool) $bool;\n\n        return $this;\n    }\n\n    /**\n     * 是否是pty模式\n     * @return bool\n     */\n    public function isPty()\n{\n        return $this->pty;\n    }\n\n    /**\n     * 获取工作目录\n     * @return string|null\n     */\n    public function getWorkingDirectory()\n{\n        if (null === $this->cwd) {\n            return getcwd() ?: null;\n        }\n\n        return $this->cwd;\n    }\n\n    /**\n     * 设置工作目录\n     * @param string $cwd\n     * @return self\n     */\n    public function setWorkingDirectory($cwd)\n{\n        $this->cwd = $cwd;\n\n        return $this;\n    }\n\n    /**\n     * 获取环境变量\n     * @return array\n     */\n    public function getEnv()\n{\n        return $this->env;\n    }\n\n    /**\n     * 设置环境变量\n     * @param array $env\n     * @return self\n     */\n    public function setEnv(array $env)\n{\n        $env = array_filter($env, function ($value) {\n            return !is_array($value);\n        });\n\n        $this->env = [];\n        foreach ($env as $key => $value) {\n            $this->env[(binary) $key] = (binary) $value;\n        }\n\n        return $this;\n    }\n\n    /**\n     * 获取输入\n     * @return null|string\n     */\n    public function getInput()\n{\n        return $this->input;\n    }\n\n    /**\n     * 设置输入\n     * @param mixed $input\n     * @return self\n     */\n    public function setInput($input)\n{\n        if ($this->isRunning()) {\n            throw new \\LogicException('Input can not be set while the process is running.');\n        }\n\n        $this->input = Utils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input);\n\n        return $this;\n    }\n\n    /**\n     * 获取proc_open的选项\n     * @return array\n     */\n    public function getOptions()\n{\n        return $this->options;\n    }\n\n    /**\n     * 设置proc_open的选项\n     * @param array $options\n     * @return self\n     */\n    public function setOptions(array $options)\n{\n        $this->options = $options;\n\n        return $this;\n    }\n\n    /**\n     * 是否兼容windows\n     * @return bool\n     */\n    public function getEnhanceWindowsCompatibility()\n{\n        return $this->enhanceWindowsCompatibility;\n    }\n\n    /**\n     * 设置是否兼容windows\n     * @param bool $enhance\n     * @return self\n     */\n    public function setEnhanceWindowsCompatibility($enhance)\n{\n        $this->enhanceWindowsCompatibility = (bool) $enhance;\n\n        return $this;\n    }\n\n    /**\n     * 返回是否 sigchild 兼容模式激活\n     * @return bool\n     */\n    public function getEnhanceSigchildCompatibility()\n{\n        return $this->enhanceSigchildCompatibility;\n    }\n\n    /**\n     * 激活 sigchild 兼容性模式。\n     * @param bool $enhance\n     * @return self\n     */\n    public function setEnhanceSigchildCompatibility($enhance)\n{\n        $this->enhanceSigchildCompatibility = (bool) $enhance;\n\n        return $this;\n    }\n\n    /**\n     * 是否超时\n     */\n    public function checkTimeout()\n{\n        if (self::STATUS_STARTED !== $this->status) {\n            return;\n        }\n\n        if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {\n            $this->stop();\n\n            throw new ProcessTimeoutException($this, ProcessTimeoutException::TYPE_GENERAL);\n        }\n\n        if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {\n            $this->stop();\n\n            throw new ProcessTimeoutException($this, ProcessTimeoutException::TYPE_IDLE);\n        }\n    }\n\n    /**\n     * 是否支持pty\n     * @return bool\n     */\n    public static function isPtySupported()\n{\n        static $result;\n\n        if (null !== $result) {\n            return $result;\n        }\n\n        if ('\\\\' === DS) {\n            return $result = false;\n        }\n\n        $proc = @proc_open('echo 1', [['pty'], ['pty'], ['pty']], $pipes);\n        if (is_resource($proc)) {\n            proc_close($proc);\n\n            return $result = true;\n        }\n\n        return $result = false;\n    }\n\n    /**\n     * 创建所需的 proc_open 的描述符\n     * @return array\n     */\n    private function getDescriptors()\n{\n        if ('\\\\' === DS) {\n            $this->processPipes = WindowsPipes::create($this, $this->input);\n        } else {\n            $this->processPipes = UnixPipes::create($this, $this->input);\n        }\n        $descriptors = $this->processPipes->getDescriptors($this->outputDisabled);\n\n        if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {\n\n            $descriptors = array_merge($descriptors, [['pipe', 'w']]);\n\n            $this->commandline = '(' . $this->commandline . ') 3>/dev/null; code=$?; echo $code >&3; exit $code';\n        }\n\n        return $descriptors;\n    }\n\n    /**\n     * 建立 wait () 使用的回调。\n     * @param callable|null $callback\n     * @return callable\n     */\n    protected function buildCallback($callback)\n{\n        $out      = self::OUT;\n        $callback = function ($type, $data) use ($callback, $out) {\n            if ($out == $type) {\n                $this->addOutput($data);\n            } else {\n                $this->addErrorOutput($data);\n            }\n\n            if (null !== $callback) {\n                call_user_func($callback, $type, $data);\n            }\n        };\n\n        return $callback;\n    }\n\n    /**\n     * 更新状态\n     * @param bool $blocking\n     */\n    protected function updateStatus($blocking)\n{\n        if (self::STATUS_STARTED !== $this->status) {\n            return;\n        }\n\n        $this->processInformation = proc_get_status($this->process);\n        $this->captureExitCode();\n\n        $this->readPipes($blocking, '\\\\' === DS ? !$this->processInformation['running'] : true);\n\n        if (!$this->processInformation['running']) {\n            $this->close();\n        }\n    }\n\n    /**\n     * 是否开启 '--enable-sigchild'\n     * @return bool\n     */\n    protected function isSigchildEnabled()\n{\n        if (null !== self::$sigchild) {\n            return self::$sigchild;\n        }\n\n        if (!function_exists('phpinfo')) {\n            return self::$sigchild = false;\n        }\n\n        ob_start();\n        phpinfo(INFO_GENERAL);\n\n        return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild');\n    }\n\n    /**\n     * 验证是否超时\n     * @param int|float|null $timeout\n     * @return float|null\n     */\n    private function validateTimeout($timeout)\n{\n        $timeout = (float) $timeout;\n\n        if (0.0 === $timeout) {\n            $timeout = null;\n        } elseif ($timeout < 0) {\n            throw new \\InvalidArgumentException('The timeout value must be a valid positive integer or float number.');\n        }\n\n        return $timeout;\n    }\n\n    /**\n     * 读取pipes\n     * @param bool $blocking\n     * @param bool $close\n     */\n    private function readPipes($blocking, $close)\n{\n        $result = $this->processPipes->readAndWrite($blocking, $close);\n\n        $callback = $this->callback;\n        foreach ($result as $type => $data) {\n            if (3 == $type) {\n                $this->fallbackExitcode = (int) $data;\n            } else {\n                $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);\n            }\n        }\n    }\n\n    /**\n     * 捕获退出码\n     */\n    private function captureExitCode()\n{\n        if (isset($this->processInformation['exitcode']) && -1 != $this->processInformation['exitcode']) {\n            $this->exitcode = $this->processInformation['exitcode'];\n        }\n    }\n\n    /**\n     * 关闭资源\n     * @return int 退出码\n     */\n    private function close()\n{\n        $this->processPipes->close();\n        if (is_resource($this->process)) {\n            $exitcode = proc_close($this->process);\n        } else {\n            $exitcode = -1;\n        }\n\n        $this->exitcode = -1 !== $exitcode ? $exitcode : (null !== $this->exitcode ? $this->exitcode : -1);\n        $this->status   = self::STATUS_TERMINATED;\n\n        if (-1 === $this->exitcode && null !== $this->fallbackExitcode) {\n            $this->exitcode = $this->fallbackExitcode;\n        } elseif (-1 === $this->exitcode && $this->processInformation['signaled']\n            && 0 < $this->processInformation['termsig']\n        ) {\n            $this->exitcode = 128 + $this->processInformation['termsig'];\n        }\n\n        return $this->exitcode;\n    }\n\n    /**\n     * 重置数据\n     */\n    private function resetProcessData()\n{\n        $this->starttime                    = null;\n        $this->callback                     = null;\n        $this->exitcode                     = null;\n        $this->fallbackExitcode             = null;\n        $this->processInformation           = null;\n        $this->stdout                       = null;\n        $this->stderr                       = null;\n        $this->process                      = null;\n        $this->latestSignal                 = null;\n        $this->status                       = self::STATUS_READY;\n        $this->incrementalOutputOffset      = 0;\n        $this->incrementalErrorOutputOffset = 0;\n    }\n\n    /**\n     * 将一个 POSIX 信号发送到进程中。\n     * @param int  $signal\n     * @param bool $throwException\n     * @return bool\n     */\n    private function doSignal($signal, $throwException)\n{\n        if (!$this->isRunning()) {\n            if ($throwException) {\n                throw new \\LogicException('Can not send signal on a non running process.');\n            }\n\n            return false;\n        }\n\n        if ($this->isSigchildEnabled()) {\n            if ($throwException) {\n                throw new \\RuntimeException('This PHP has been compiled with --enable-sigchild. The process can not be signaled.');\n            }\n\n            return false;\n        }\n\n        if (true !== @proc_terminate($this->process, $signal)) {\n            if ($throwException) {\n                throw new \\RuntimeException(sprintf('Error while sending signal `%s`.', $signal));\n            }\n\n            return false;\n        }\n\n        $this->latestSignal = $signal;\n\n        return true;\n    }\n\n    /**\n     * 确保进程已经开启\n     * @param string $functionName\n     */\n    private function requireProcessIsStarted($functionName)\n{\n        if (!$this->isStarted()) {\n            throw new \\LogicException(sprintf('Process must be started before calling %s.', $functionName));\n        }\n    }\n\n    /**\n     * 确保进程已经终止\n     * @param string $functionName\n     */\n    private function requireProcessIsTerminated($functionName)\n{\n        if (!$this->isTerminated()) {\n            throw new \\LogicException(sprintf('Process must be terminated before calling %s.', $functionName));\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Request.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nclass Request\n{\n    /**\n     * @var object 对象实例\n     */\n    protected static $instance;\n\n    protected $method;\n    /**\n     * @var string 域名（含协议和端口）\n     */\n    protected $domain;\n\n    /**\n     * @var string URL地址\n     */\n    protected $url;\n\n    /**\n     * @var string 基础URL\n     */\n    protected $baseUrl;\n\n    /**\n     * @var string 当前执行的文件\n     */\n    protected $baseFile;\n\n    /**\n     * @var string 访问的ROOT地址\n     */\n    protected $root;\n\n    /**\n     * @var string pathinfo\n     */\n    protected $pathinfo;\n\n    /**\n     * @var string pathinfo（不含后缀）\n     */\n    protected $path;\n\n    /**\n     * @var array 当前路由信息\n     */\n    protected $routeInfo = [];\n\n    /**\n     * @var array 当前调度信息\n     */\n    protected $dispatch = [];\n    protected $module;\n    protected $controller;\n    protected $action;\n    // 当前语言集\n    protected $langset;\n\n    /**\n     * @var array 请求参数\n     */\n    protected $param   = [];\n    protected $get     = [];\n    protected $post    = [];\n    protected $request = [];\n    protected $route   = [];\n    protected $put;\n    protected $session = [];\n    protected $file    = [];\n    protected $cookie  = [];\n    protected $server  = [];\n    protected $header  = [];\n\n    /**\n     * @var array 资源类型\n     */\n    protected $mimeType = [\n        'xml'   => 'application/xml,text/xml,application/x-xml',\n        'json'  => 'application/json,text/x-json,application/jsonrequest,text/json',\n        'js'    => 'text/javascript,application/javascript,application/x-javascript',\n        'css'   => 'text/css',\n        'rss'   => 'application/rss+xml',\n        'yaml'  => 'application/x-yaml,text/yaml',\n        'atom'  => 'application/atom+xml',\n        'pdf'   => 'application/pdf',\n        'text'  => 'text/plain',\n        'image' => 'image/png,image/jpg,image/jpeg,image/pjpeg,image/gif,image/webp,image/*',\n        'csv'   => 'text/csv',\n        'html'  => 'text/html,application/xhtml+xml,*/*',\n    ];\n\n    protected $content;\n\n    // 全局过滤规则\n    protected $filter;\n    // Hook扩展方法\n    protected static $hook = [];\n    // 绑定的属性\n    protected $bind = [];\n    // php://input\n    protected $input;\n    // 请求缓存\n    protected $cache;\n    // 缓存是否检查\n    protected $isCheckCache;\n\n    /**\n     * 构造函数\n     * @access protected\n     * @param array $options 参数\n     */\n    protected function __construct($options = [])\n    {\n        foreach ($options as $name => $item) {\n            if (property_exists($this, $name)) {\n                $this->$name = $item;\n            }\n        }\n        if (is_null($this->filter)) {\n            $this->filter = Config::get('default_filter');\n        }\n\n        // 保存 php://input\n        $this->input = file_get_contents('php://input');\n    }\n\n    public function __call($method, $args)\n    {\n        if (array_key_exists($method, self::$hook)) {\n            array_unshift($args, $this);\n            return call_user_func_array(self::$hook[$method], $args);\n        } else {\n            throw new Exception('method not exists:' . __CLASS__ . '->' . $method);\n        }\n    }\n\n    /**\n     * Hook 方法注入\n     * @access public\n     * @param string|array  $method 方法名\n     * @param mixed         $callback callable\n     * @return void\n     */\n    public static function hook($method, $callback = null)\n    {\n        if (is_array($method)) {\n            self::$hook = array_merge(self::$hook, $method);\n        } else {\n            self::$hook[$method] = $callback;\n        }\n    }\n\n    /**\n     * 初始化\n     * @access public\n     * @param array $options 参数\n     * @return \\think\\Request\n     */\n    public static function instance($options = [])\n    {\n        if (is_null(self::$instance)) {\n            self::$instance = new static($options);\n        }\n        return self::$instance;\n    }\n\n    /**\n     * 创建一个URL请求\n     * @access public\n     * @param string    $uri URL地址\n     * @param string    $method 请求类型\n     * @param array     $params 请求参数\n     * @param array     $cookie\n     * @param array     $files\n     * @param array     $server\n     * @param string    $content\n     * @return \\think\\Request\n     */\n    public static function create($uri, $method = 'GET', $params = [], $cookie = [], $files = [], $server = [], $content = null)\n    {\n        $server['PATH_INFO']      = '';\n        $server['REQUEST_METHOD'] = strtoupper($method);\n        $info                     = parse_url($uri);\n        if (isset($info['host'])) {\n            $server['SERVER_NAME'] = $info['host'];\n            $server['HTTP_HOST']   = $info['host'];\n        }\n        if (isset($info['scheme'])) {\n            if ('https' === $info['scheme']) {\n                $server['HTTPS']       = 'on';\n                $server['SERVER_PORT'] = 443;\n            } else {\n                unset($server['HTTPS']);\n                $server['SERVER_PORT'] = 80;\n            }\n        }\n        if (isset($info['port'])) {\n            $server['SERVER_PORT'] = $info['port'];\n            $server['HTTP_HOST']   = $server['HTTP_HOST'] . ':' . $info['port'];\n        }\n        if (isset($info['user'])) {\n            $server['PHP_AUTH_USER'] = $info['user'];\n        }\n        if (isset($info['pass'])) {\n            $server['PHP_AUTH_PW'] = $info['pass'];\n        }\n        if (!isset($info['path'])) {\n            $info['path'] = '/';\n        }\n        $options                      = [];\n        $options[strtolower($method)] = $params;\n        $queryString                  = '';\n        if (isset($info['query'])) {\n            parse_str(html_entity_decode($info['query']), $query);\n            if (!empty($params)) {\n                $params      = array_replace($query, $params);\n                $queryString = http_build_query($query, '', '&');\n            } else {\n                $params      = $query;\n                $queryString = $info['query'];\n            }\n        } elseif (!empty($params)) {\n            $queryString = http_build_query($params, '', '&');\n        }\n        if ($queryString) {\n            parse_str($queryString, $get);\n            $options['get'] = isset($options['get']) ? array_merge($get, $options['get']) : $get;\n        }\n\n        $server['REQUEST_URI']  = $info['path'] . ('' !== $queryString ? '?' . $queryString : '');\n        $server['QUERY_STRING'] = $queryString;\n        $options['cookie']      = $cookie;\n        $options['param']       = $params;\n        $options['file']        = $files;\n        $options['server']      = $server;\n        $options['url']         = $server['REQUEST_URI'];\n        $options['baseUrl']     = $info['path'];\n        $options['pathinfo']    = '/' == $info['path'] ? '/' : ltrim($info['path'], '/');\n        $options['method']      = $server['REQUEST_METHOD'];\n        $options['domain']      = isset($info['scheme']) ? $info['scheme'] . '://' . $server['HTTP_HOST'] : '';\n        $options['content']     = $content;\n        self::$instance         = new self($options);\n        return self::$instance;\n    }\n\n    /**\n     * 设置或获取当前包含协议的域名\n     * @access public\n     * @param string $domain 域名\n     * @return string\n     */\n    public function domain($domain = null)\n    {\n        if (!is_null($domain)) {\n            $this->domain = $domain;\n            return $this;\n        } elseif (!$this->domain) {\n            $this->domain = $this->scheme() . '://' . $this->host();\n        }\n        return $this->domain;\n    }\n\n    /**\n     * 设置或获取当前完整URL 包括QUERY_STRING\n     * @access public\n     * @param string|true $url URL地址 true 带域名获取\n     * @return string\n     */\n    public function url($url = null)\n    {\n        if (!is_null($url) && true !== $url) {\n            $this->url = $url;\n            return $this;\n        } elseif (!$this->url) {\n            if (IS_CLI) {\n                $this->url = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';\n            } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) {\n                $this->url = $_SERVER['HTTP_X_REWRITE_URL'];\n            } elseif (isset($_SERVER['REQUEST_URI'])) {\n                $this->url = $_SERVER['REQUEST_URI'];\n            } elseif (isset($_SERVER['ORIG_PATH_INFO'])) {\n                $this->url = $_SERVER['ORIG_PATH_INFO'] . (!empty($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '');\n            } else {\n                $this->url = '';\n            }\n        }\n        return true === $url ? $this->domain() . $this->url : $this->url;\n    }\n\n    /**\n     * 设置或获取当前URL 不含QUERY_STRING\n     * @access public\n     * @param string $url URL地址\n     * @return string\n     */\n    public function baseUrl($url = null)\n    {\n        if (!is_null($url) && true !== $url) {\n            $this->baseUrl = $url;\n            return $this;\n        } elseif (!$this->baseUrl) {\n            $str           = $this->url();\n            $this->baseUrl = strpos($str, '?') ? strstr($str, '?', true) : $str;\n        }\n        return true === $url ? $this->domain() . $this->baseUrl : $this->baseUrl;\n    }\n\n    /**\n     * 设置或获取当前执行的文件 SCRIPT_NAME\n     * @access public\n     * @param string $file 当前执行的文件\n     * @return string\n     */\n    public function baseFile($file = null)\n    {\n        if (!is_null($file) && true !== $file) {\n            $this->baseFile = $file;\n            return $this;\n        } elseif (!$this->baseFile) {\n            $url = '';\n            if (!IS_CLI) {\n                $script_name = basename($_SERVER['SCRIPT_FILENAME']);\n                if (basename($_SERVER['SCRIPT_NAME']) === $script_name) {\n                    $url = $_SERVER['SCRIPT_NAME'];\n                } elseif (basename($_SERVER['PHP_SELF']) === $script_name) {\n                    $url = $_SERVER['PHP_SELF'];\n                } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $script_name) {\n                    $url = $_SERVER['ORIG_SCRIPT_NAME'];\n                } elseif (($pos = strpos($_SERVER['PHP_SELF'], '/' . $script_name)) !== false) {\n                    $url = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $script_name;\n                } elseif (isset($_SERVER['DOCUMENT_ROOT']) && strpos($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT']) === 0) {\n                    $url = str_replace('\\\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_FILENAME']));\n                }\n            }\n            $this->baseFile = $url;\n        }\n        return true === $file ? $this->domain() . $this->baseFile : $this->baseFile;\n    }\n\n    /**\n     * 设置或获取URL访问根地址\n     * @access public\n     * @param string $url URL地址\n     * @return string\n     */\n    public function root($url = null)\n    {\n        if (!is_null($url) && true !== $url) {\n            $this->root = $url;\n            return $this;\n        } elseif (!$this->root) {\n            $file = $this->baseFile();\n            if ($file && 0 !== strpos($this->url(), $file)) {\n                $file = str_replace('\\\\', '/', dirname($file));\n            }\n            $this->root = rtrim($file, '/');\n        }\n        return true === $url ? $this->domain() . $this->root : $this->root;\n    }\n\n    /**\n     * 获取当前请求URL的pathinfo信息（含URL后缀）\n     * @access public\n     * @return string\n     */\n    public function pathinfo()\n    {\n        if (is_null($this->pathinfo)) {\n            if (isset($_GET[Config::get('var_pathinfo')])) {\n                // 判断URL里面是否有兼容模式参数\n                $_SERVER['PATH_INFO'] = $_GET[Config::get('var_pathinfo')];\n                unset($_GET[Config::get('var_pathinfo')]);\n            } elseif (IS_CLI) {\n                // CLI模式下 index.php module/controller/action/params/...\n                $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';\n            }\n\n            // 分析PATHINFO信息\n            if (!isset($_SERVER['PATH_INFO'])) {\n                foreach (Config::get('pathinfo_fetch') as $type) {\n                    if (!empty($_SERVER[$type])) {\n                        $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type], $_SERVER['SCRIPT_NAME'])) ?\n                        substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type];\n                        break;\n                    }\n                }\n            }\n            $this->pathinfo = empty($_SERVER['PATH_INFO']) ? '/' : ltrim($_SERVER['PATH_INFO'], '/');\n        }\n        return $this->pathinfo;\n    }\n\n    /**\n     * 获取当前请求URL的pathinfo信息(不含URL后缀)\n     * @access public\n     * @return string\n     */\n    public function path()\n    {\n        if (is_null($this->path)) {\n            $suffix   = Config::get('url_html_suffix');\n            $pathinfo = $this->pathinfo();\n            if (false === $suffix) {\n                // 禁止伪静态访问\n                $this->path = $pathinfo;\n            } elseif ($suffix) {\n                // 去除正常的URL后缀\n                $this->path = preg_replace('/\\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);\n            } else {\n                // 允许任何后缀访问\n                $this->path = preg_replace('/\\.' . $this->ext() . '$/i', '', $pathinfo);\n            }\n        }\n        return $this->path;\n    }\n\n    /**\n     * 当前URL的访问后缀\n     * @access public\n     * @return string\n     */\n    public function ext()\n    {\n        return pathinfo($this->pathinfo(), PATHINFO_EXTENSION);\n    }\n\n    /**\n     * 获取当前请求的时间\n     * @access public\n     * @param bool $float 是否使用浮点类型\n     * @return integer|float\n     */\n    public function time($float = false)\n    {\n        return $float ? $_SERVER['REQUEST_TIME_FLOAT'] : $_SERVER['REQUEST_TIME'];\n    }\n\n    /**\n     * 当前请求的资源类型\n     * @access public\n     * @return false|string\n     */\n    public function type()\n    {\n        $accept = $this->server('HTTP_ACCEPT');\n        if (empty($accept)) {\n            return false;\n        }\n\n        foreach ($this->mimeType as $key => $val) {\n            $array = explode(',', $val);\n            foreach ($array as $k => $v) {\n                if (stristr($accept, $v)) {\n                    return $key;\n                }\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 设置资源类型\n     * @access public\n     * @param string|array  $type 资源类型名\n     * @param string        $val 资源类型\n     * @return void\n     */\n    public function mimeType($type, $val = '')\n    {\n        if (is_array($type)) {\n            $this->mimeType = array_merge($this->mimeType, $type);\n        } else {\n            $this->mimeType[$type] = $val;\n        }\n    }\n\n    /**\n     * 当前的请求类型\n     * @access public\n     * @param bool $method  true 获取原始请求类型\n     * @return string\n     */\n    public function method($method = false)\n    {\n        if (true === $method) {\n            // 获取原始请求类型\n            return IS_CLI ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']);\n        } elseif (!$this->method) {\n            if (isset($_POST[Config::get('var_method')])) {\n                $this->method = strtoupper($_POST[Config::get('var_method')]);\n                $this->{$this->method}($_POST);\n            } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {\n                $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);\n            } else {\n                $this->method = IS_CLI ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']);\n            }\n        }\n        return $this->method;\n    }\n\n    /**\n     * 是否为GET请求\n     * @access public\n     * @return bool\n     */\n    public function isGet()\n    {\n        return $this->method() == 'GET';\n    }\n\n    /**\n     * 是否为POST请求\n     * @access public\n     * @return bool\n     */\n    public function isPost()\n    {\n        return $this->method() == 'POST';\n    }\n\n    /**\n     * 是否为PUT请求\n     * @access public\n     * @return bool\n     */\n    public function isPut()\n    {\n        return $this->method() == 'PUT';\n    }\n\n    /**\n     * 是否为DELTE请求\n     * @access public\n     * @return bool\n     */\n    public function isDelete()\n    {\n        return $this->method() == 'DELETE';\n    }\n\n    /**\n     * 是否为HEAD请求\n     * @access public\n     * @return bool\n     */\n    public function isHead()\n    {\n        return $this->method() == 'HEAD';\n    }\n\n    /**\n     * 是否为PATCH请求\n     * @access public\n     * @return bool\n     */\n    public function isPatch()\n    {\n        return $this->method() == 'PATCH';\n    }\n\n    /**\n     * 是否为OPTIONS请求\n     * @access public\n     * @return bool\n     */\n    public function isOptions()\n    {\n        return $this->method() == 'OPTIONS';\n    }\n\n    /**\n     * 是否为cli\n     * @access public\n     * @return bool\n     */\n    public function isCli()\n    {\n        return PHP_SAPI == 'cli';\n    }\n\n    /**\n     * 是否为cgi\n     * @access public\n     * @return bool\n     */\n    public function isCgi()\n    {\n        return strpos(PHP_SAPI, 'cgi') === 0;\n    }\n\n    /**\n     * 获取当前请求的参数\n     * @access public\n     * @param string|array  $name 变量名\n     * @param mixed         $default 默认值\n     * @param string|array  $filter 过滤方法\n     * @return mixed\n     */\n    public function param($name = '', $default = null, $filter = '')\n    {\n        if (empty($this->param)) {\n            $method = $this->method(true);\n            // 自动获取请求变量\n            switch ($method) {\n                case 'POST':\n                    $vars = $this->post(false);\n                    break;\n                case 'PUT':\n                case 'DELETE':\n                case 'PATCH':\n                    $vars = $this->put(false);\n                    break;\n                default:\n                    $vars = [];\n            }\n            // 当前请求参数和URL地址中的参数合并\n            $this->param = array_merge($this->get(false), $vars, $this->route(false));\n        }\n        if (true === $name) {\n            // 获取包含文件上传信息的数组\n            $file = $this->file();\n            $data = is_array($file) ? array_merge($this->param, $file) : $this->param;\n            return $this->input($data, '', $default, $filter);\n        }\n        return $this->input($this->param, $name, $default, $filter);\n    }\n\n    /**\n     * 设置获取路由参数\n     * @access public\n     * @param string|array  $name 变量名\n     * @param mixed         $default 默认值\n     * @param string|array  $filter 过滤方法\n     * @return mixed\n     */\n    public function route($name = '', $default = null, $filter = '')\n    {\n        if (is_array($name)) {\n            $this->param        = [];\n            return $this->route = array_merge($this->route, $name);\n        }\n        return $this->input($this->route, $name, $default, $filter);\n    }\n\n    /**\n     * 设置获取GET参数\n     * @access public\n     * @param string|array  $name 变量名\n     * @param mixed         $default 默认值\n     * @param string|array  $filter 过滤方法\n     * @return mixed\n     */\n    public function get($name = '', $default = null, $filter = '')\n    {\n        if (empty($this->get)) {\n            $this->get = $_GET;\n        }\n        if (is_array($name)) {\n            $this->param      = [];\n            return $this->get = array_merge($this->get, $name);\n        }\n        return $this->input($this->get, $name, $default, $filter);\n    }\n\n    /**\n     * 设置获取POST参数\n     * @access public\n     * @param string        $name 变量名\n     * @param mixed         $default 默认值\n     * @param string|array  $filter 过滤方法\n     * @return mixed\n     */\n    public function post($name = '', $default = null, $filter = '')\n    {\n        if (empty($this->post)) {\n            $content = $this->input;\n            if (empty($_POST) && false !== strpos($this->contentType(), 'application/json')) {\n                $this->post = (array) json_decode($content, true);\n            } else {\n                $this->post = $_POST;\n            }\n        }\n        if (is_array($name)) {\n            $this->param       = [];\n            return $this->post = array_merge($this->post, $name);\n        }\n        return $this->input($this->post, $name, $default, $filter);\n    }\n\n    /**\n     * 设置获取PUT参数\n     * @access public\n     * @param string|array      $name 变量名\n     * @param mixed             $default 默认值\n     * @param string|array      $filter 过滤方法\n     * @return mixed\n     */\n    public function put($name = '', $default = null, $filter = '')\n    {\n        if (is_null($this->put)) {\n            $content = $this->input;\n            if (false !== strpos($this->contentType(), 'application/json')) {\n                $this->put = (array) json_decode($content, true);\n            } else {\n                parse_str($content, $this->put);\n            }\n        }\n        if (is_array($name)) {\n            $this->param      = [];\n            return $this->put = is_null($this->put) ? $name : array_merge($this->put, $name);\n        }\n\n        return $this->input($this->put, $name, $default, $filter);\n    }\n\n    /**\n     * 设置获取DELETE参数\n     * @access public\n     * @param string|array      $name 变量名\n     * @param mixed             $default 默认值\n     * @param string|array      $filter 过滤方法\n     * @return mixed\n     */\n    public function delete($name = '', $default = null, $filter = '')\n    {\n        return $this->put($name, $default, $filter);\n    }\n\n    /**\n     * 设置获取PATCH参数\n     * @access public\n     * @param string|array      $name 变量名\n     * @param mixed             $default 默认值\n     * @param string|array      $filter 过滤方法\n     * @return mixed\n     */\n    public function patch($name = '', $default = null, $filter = '')\n    {\n        return $this->put($name, $default, $filter);\n    }\n\n    /**\n     * 获取request变量\n     * @param string        $name 数据名称\n     * @param string        $default 默认值\n     * @param string|array  $filter 过滤方法\n     * @return mixed\n     */\n    public function request($name = '', $default = null, $filter = '')\n    {\n        if (empty($this->request)) {\n            $this->request = $_REQUEST;\n        }\n        if (is_array($name)) {\n            $this->param          = [];\n            return $this->request = array_merge($this->request, $name);\n        }\n        return $this->input($this->request, $name, $default, $filter);\n    }\n\n    /**\n     * 获取session数据\n     * @access public\n     * @param string|array  $name 数据名称\n     * @param string        $default 默认值\n     * @param string|array  $filter 过滤方法\n     * @return mixed\n     */\n    public function session($name = '', $default = null, $filter = '')\n    {\n        if (empty($this->session)) {\n            $this->session = Session::get();\n        }\n        if (is_array($name)) {\n            return $this->session = array_merge($this->session, $name);\n        }\n        return $this->input($this->session, $name, $default, $filter);\n    }\n\n    /**\n     * 获取cookie参数\n     * @access public\n     * @param string|array  $name 数据名称\n     * @param string        $default 默认值\n     * @param string|array  $filter 过滤方法\n     * @return mixed\n     */\n    public function cookie($name = '', $default = null, $filter = '')\n    {\n        if (empty($this->cookie)) {\n            $this->cookie = Cookie::get();\n        }\n        if (is_array($name)) {\n            return $this->cookie = array_merge($this->cookie, $name);\n        } elseif (!empty($name)) {\n            $data = Cookie::has($name) ? Cookie::get($name) : $default;\n        } else {\n            $data = $this->cookie;\n        }\n\n        // 解析过滤器\n        $filter = $this->getFilter($filter, $default);\n\n        if (is_array($data)) {\n            array_walk_recursive($data, [$this, 'filterValue'], $filter);\n            reset($data);\n        } else {\n            $this->filterValue($data, $name, $filter);\n        }\n        return $data;\n    }\n\n    /**\n     * 获取server参数\n     * @access public\n     * @param string|array  $name 数据名称\n     * @param string        $default 默认值\n     * @param string|array  $filter 过滤方法\n     * @return mixed\n     */\n    public function server($name = '', $default = null, $filter = '')\n    {\n        if (empty($this->server)) {\n            $this->server = $_SERVER;\n        }\n        if (is_array($name)) {\n            return $this->server = array_merge($this->server, $name);\n        }\n        return $this->input($this->server, false === $name ? false : strtoupper($name), $default, $filter);\n    }\n\n    /**\n     * 获取上传的文件信息\n     * @access public\n     * @param string|array $name 名称\n     * @return null|array|\\think\\File\n     */\n    public function file($name = '')\n    {\n        if (empty($this->file)) {\n            $this->file = isset($_FILES) ? $_FILES : [];\n        }\n        if (is_array($name)) {\n            return $this->file = array_merge($this->file, $name);\n        }\n        $files = $this->file;\n        if (!empty($files)) {\n            // 处理上传文件\n            $array = [];\n            foreach ($files as $key => $file) {\n                if (is_array($file['name'])) {\n                    $item  = [];\n                    $keys  = array_keys($file);\n                    $count = count($file['name']);\n                    for ($i = 0; $i < $count; $i++) {\n                        if (empty($file['tmp_name'][$i]) || !is_file($file['tmp_name'][$i])) {\n                            continue;\n                        }\n                        $temp['key'] = $key;\n                        foreach ($keys as $_key) {\n                            $temp[$_key] = $file[$_key][$i];\n                        }\n                        $item[] = (new File($temp['tmp_name']))->setUploadInfo($temp);\n                    }\n                    $array[$key] = $item;\n                } else {\n                    if ($file instanceof File) {\n                        $array[$key] = $file;\n                    } else {\n                        if (empty($file['tmp_name']) || !is_file($file['tmp_name'])) {\n                            continue;\n                        }\n                        $array[$key] = (new File($file['tmp_name']))->setUploadInfo($file);\n                    }\n                }\n            }\n            if (strpos($name, '.')) {\n                list($name, $sub) = explode('.', $name);\n            }\n            if ('' === $name) {\n                // 获取全部文件\n                return $array;\n            } elseif (isset($sub) && isset($array[$name][$sub])) {\n                return $array[$name][$sub];\n            } elseif (isset($array[$name])) {\n                return $array[$name];\n            }\n        }\n        return;\n    }\n\n    /**\n     * 获取环境变量\n     * @param string|array  $name 数据名称\n     * @param string        $default 默认值\n     * @param string|array  $filter 过滤方法\n     * @return mixed\n     */\n    public function env($name = '', $default = null, $filter = '')\n    {\n        if (empty($this->env)) {\n            $this->env = $_ENV;\n        }\n        if (is_array($name)) {\n            return $this->env = array_merge($this->env, $name);\n        }\n        return $this->input($this->env, false === $name ? false : strtoupper($name), $default, $filter);\n    }\n\n    /**\n     * 设置或者获取当前的Header\n     * @access public\n     * @param string|array  $name header名称\n     * @param string        $default 默认值\n     * @return string\n     */\n    public function header($name = '', $default = null)\n    {\n        if (empty($this->header)) {\n            $header = [];\n            if (function_exists('apache_request_headers') && $result = apache_request_headers()) {\n                $header = $result;\n            } else {\n                $server = $this->server ?: $_SERVER;\n                foreach ($server as $key => $val) {\n                    if (0 === strpos($key, 'HTTP_')) {\n                        $key          = str_replace('_', '-', strtolower(substr($key, 5)));\n                        $header[$key] = $val;\n                    }\n                }\n                if (isset($server['CONTENT_TYPE'])) {\n                    $header['content-type'] = $server['CONTENT_TYPE'];\n                }\n                if (isset($server['CONTENT_LENGTH'])) {\n                    $header['content-length'] = $server['CONTENT_LENGTH'];\n                }\n            }\n            $this->header = array_change_key_case($header);\n        }\n        if (is_array($name)) {\n            return $this->header = array_merge($this->header, $name);\n        }\n        if ('' === $name) {\n            return $this->header;\n        }\n        $name = str_replace('_', '-', strtolower($name));\n        return isset($this->header[$name]) ? $this->header[$name] : $default;\n    }\n\n    /**\n     * 获取变量 支持过滤和默认值\n     * @param array         $data 数据源\n     * @param string|false  $name 字段名\n     * @param mixed         $default 默认值\n     * @param string|array  $filter 过滤函数\n     * @return mixed\n     */\n    public function input($data = [], $name = '', $default = null, $filter = '')\n    {\n        if (false === $name) {\n            // 获取原始数据\n            return $data;\n        }\n        $name = (string) $name;\n        if ('' != $name) {\n            // 解析name\n            if (strpos($name, '/')) {\n                list($name, $type) = explode('/', $name);\n            } else {\n                $type = 's';\n            }\n            // 按.拆分成多维数组进行判断\n            foreach (explode('.', $name) as $val) {\n                if (isset($data[$val])) {\n                    $data = $data[$val];\n                } else {\n                    // 无输入数据，返回默认值\n                    return $default;\n                }\n            }\n            if (is_object($data)) {\n                return $data;\n            }\n        }\n\n        // 解析过滤器\n        $filter = $this->getFilter($filter, $default);\n\n        if (is_array($data)) {\n            array_walk_recursive($data, [$this, 'filterValue'], $filter);\n            reset($data);\n        } else {\n            $this->filterValue($data, $name, $filter);\n        }\n\n        if (isset($type) && $data !== $default) {\n            // 强制类型转换\n            $this->typeCast($data, $type);\n        }\n        return $data;\n    }\n\n    /**\n     * 设置或获取当前的过滤规则\n     * @param mixed $filter 过滤规则\n     * @return mixed\n     */\n    public function filter($filter = null)\n    {\n        if (is_null($filter)) {\n            return $this->filter;\n        } else {\n            $this->filter = $filter;\n        }\n    }\n\n    protected function getFilter($filter, $default)\n    {\n        if (is_null($filter)) {\n            $filter = [];\n        } else {\n            $filter = $filter ?: $this->filter;\n            if (is_string($filter) && false === strpos($filter, '/')) {\n                $filter = explode(',', $filter);\n            } else {\n                $filter = (array) $filter;\n            }\n        }\n\n        $filter[] = $default;\n        return $filter;\n    }\n\n    /**\n     * 递归过滤给定的值\n     * @param mixed     $value 键值\n     * @param mixed     $key 键名\n     * @param array     $filters 过滤方法+默认值\n     * @return mixed\n     */\n    private function filterValue(&$value, $key, $filters)\n    {\n        $default = array_pop($filters);\n        foreach ($filters as $filter) {\n            if (is_callable($filter)) {\n                // 调用函数或者方法过滤\n                $value = call_user_func($filter, $value);\n            } elseif (is_scalar($value)) {\n                if (false !== strpos($filter, '/')) {\n                    // 正则过滤\n                    if (!preg_match($filter, $value)) {\n                        // 匹配不成功返回默认值\n                        $value = $default;\n                        break;\n                    }\n                } elseif (!empty($filter)) {\n                    // filter函数不存在时, 则使用filter_var进行过滤\n                    // filter为非整形值时, 调用filter_id取得过滤id\n                    $value = filter_var($value, is_int($filter) ? $filter : filter_id($filter));\n                    if (false === $value) {\n                        $value = $default;\n                        break;\n                    }\n                }\n            }\n        }\n        return $this->filterExp($value);\n    }\n\n    /**\n     * 过滤表单中的表达式\n     * @param string $value\n     * @return void\n     */\n    public function filterExp(&$value)\n    {\n        // 过滤查询特殊字符\n        if (is_string($value) && preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i', $value)) {\n            $value .= ' ';\n        }\n        // TODO 其他安全过滤\n    }\n\n    /**\n     * 强制类型转换\n     * @param string $data\n     * @param string $type\n     * @return mixed\n     */\n    private function typeCast(&$data, $type)\n    {\n        switch (strtolower($type)) {\n            // 数组\n            case 'a':\n                $data = (array) $data;\n                break;\n            // 数字\n            case 'd':\n                $data = (int) $data;\n                break;\n            // 浮点\n            case 'f':\n                $data = (float) $data;\n                break;\n            // 布尔\n            case 'b':\n                $data = (boolean) $data;\n                break;\n            // 字符串\n            case 's':\n            default:\n                if (is_scalar($data)) {\n                    $data = (string) $data;\n                } else {\n                    throw new \\InvalidArgumentException('variable type error：' . gettype($data));\n                }\n        }\n    }\n\n    /**\n     * 是否存在某个请求参数\n     * @access public\n     * @param string    $name 变量名\n     * @param string    $type 变量类型\n     * @param bool      $checkEmpty 是否检测空值\n     * @return mixed\n     */\n    public function has($name, $type = 'param', $checkEmpty = false)\n    {\n        if (empty($this->$type)) {\n            $param = $this->$type();\n        } else {\n            $param = $this->$type;\n        }\n        // 按.拆分成多维数组进行判断\n        foreach (explode('.', $name) as $val) {\n            if (isset($param[$val])) {\n                $param = $param[$val];\n            } else {\n                return false;\n            }\n        }\n        return ($checkEmpty && '' === $param) ? false : true;\n    }\n\n    /**\n     * 获取指定的参数\n     * @access public\n     * @param string|array  $name 变量名\n     * @param string        $type 变量类型\n     * @return mixed\n     */\n    public function only($name, $type = 'param')\n    {\n        $param = $this->$type();\n        if (is_string($name)) {\n            $name = explode(',', $name);\n        }\n        $item = [];\n        foreach ($name as $key) {\n            if (isset($param[$key])) {\n                $item[$key] = $param[$key];\n            }\n        }\n        return $item;\n    }\n\n    /**\n     * 排除指定参数获取\n     * @access public\n     * @param string|array  $name 变量名\n     * @param string        $type 变量类型\n     * @return mixed\n     */\n    public function except($name, $type = 'param')\n    {\n        $param = $this->$type();\n        if (is_string($name)) {\n            $name = explode(',', $name);\n        }\n        foreach ($name as $key) {\n            if (isset($param[$key])) {\n                unset($param[$key]);\n            }\n        }\n        return $param;\n    }\n\n    /**\n     * 当前是否ssl\n     * @access public\n     * @return bool\n     */\n    public function isSsl()\n    {\n        $server = array_merge($_SERVER, $this->server);\n        if (isset($server['HTTPS']) && ('1' == $server['HTTPS'] || 'on' == strtolower($server['HTTPS']))) {\n            return true;\n        } elseif (isset($server['REQUEST_SCHEME']) && 'https' == $server['REQUEST_SCHEME']) {\n            return true;\n        } elseif (isset($server['SERVER_PORT']) && ('443' == $server['SERVER_PORT'])) {\n            return true;\n        } elseif (isset($server['HTTP_X_FORWARDED_PROTO']) && 'https' == $server['HTTP_X_FORWARDED_PROTO']) {\n            return true;\n        } elseif (Config::get('https_agent_name') && isset($server[Config::get('https_agent_name')])) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 当前是否Ajax请求\n     * @access public\n     * @param bool $ajax  true 获取原始ajax请求\n     * @return bool\n     */\n    public function isAjax($ajax = false)\n    {\n        $value  = $this->server('HTTP_X_REQUESTED_WITH', '', 'strtolower');\n        $result = ('xmlhttprequest' == $value) ? true : false;\n        if (true === $ajax) {\n            return $result;\n        } else {\n            return $this->param(Config::get('var_ajax')) ? true : $result;\n        }\n    }\n\n    /**\n     * 当前是否Pjax请求\n     * @access public\n     * @param bool $pjax  true 获取原始pjax请求\n     * @return bool\n     */\n    public function isPjax($pjax = false)\n    {\n        $result = !is_null($this->server('HTTP_X_PJAX')) ? true : false;\n        if (true === $pjax) {\n            return $result;\n        } else {\n            return $this->param(Config::get('var_pjax')) ? true : $result;\n        }\n    }\n\n    /**\n     * 获取客户端IP地址\n     * @param integer   $type 返回类型 0 返回IP地址 1 返回IPV4地址数字\n     * @param boolean   $adv 是否进行高级模式获取（有可能被伪装）\n     * @return mixed\n     */\n    public function ip($type = 0, $adv = false)\n    {\n        $type      = $type ? 1 : 0;\n        static $ip = null;\n        if (null !== $ip) {\n            return $ip[$type];\n        }\n\n        if ($adv) {\n            if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {\n                $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);\n                $pos = array_search('unknown', $arr);\n                if (false !== $pos) {\n                    unset($arr[$pos]);\n                }\n                $ip = trim(current($arr));\n            } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {\n                $ip = $_SERVER['HTTP_CLIENT_IP'];\n            } elseif (isset($_SERVER['REMOTE_ADDR'])) {\n                $ip = $_SERVER['REMOTE_ADDR'];\n            }\n        } elseif (isset($_SERVER['REMOTE_ADDR'])) {\n            $ip = $_SERVER['REMOTE_ADDR'];\n        }\n        // IP地址合法验证\n        $long = sprintf(\"%u\", ip2long($ip));\n        $ip   = $long ? [$ip, $long] : ['0.0.0.0', 0];\n        return $ip[$type];\n    }\n\n    /**\n     * 检测是否使用手机访问\n     * @access public\n     * @return bool\n     */\n    public function isMobile()\n    {\n        if (isset($_SERVER['HTTP_VIA']) && stristr($_SERVER['HTTP_VIA'], \"wap\")) {\n            return true;\n        } elseif (isset($_SERVER['HTTP_ACCEPT']) && strpos(strtoupper($_SERVER['HTTP_ACCEPT']), \"VND.WAP.WML\")) {\n            return true;\n        } elseif (isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_PROFILE'])) {\n            return true;\n        } elseif (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/(blackberry|configuration\\/cldc|hp |hp-|htc |htc_|htc-|iemobile|kindle|midp|mmp|motorola|mobile|nokia|opera mini|opera |Googlebot-Mobile|YahooSeeker\\/M1A1-R2D2|android|iphone|ipod|mobi|palm|palmos|pocket|portalmmm|ppc;|smartphone|sonyericsson|sqh|spv|symbian|treo|up.browser|up.link|vodafone|windows ce|xda |xda_)/i', $_SERVER['HTTP_USER_AGENT'])) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * 当前URL地址中的scheme参数\n     * @access public\n     * @return string\n     */\n    public function scheme()\n    {\n        return $this->isSsl() ? 'https' : 'http';\n    }\n\n    /**\n     * 当前请求URL地址中的query参数\n     * @access public\n     * @return string\n     */\n    public function query()\n    {\n        return $this->server('QUERY_STRING');\n    }\n\n    /**\n     * 当前请求的host\n     * @access public\n     * @return string\n     */\n    public function host()\n    {\n        return $this->server('HTTP_HOST');\n    }\n\n    /**\n     * 当前请求URL地址中的port参数\n     * @access public\n     * @return integer\n     */\n    public function port()\n    {\n        return $this->server('SERVER_PORT');\n    }\n\n    /**\n     * 当前请求 SERVER_PROTOCOL\n     * @access public\n     * @return integer\n     */\n    public function protocol()\n    {\n        return $this->server('SERVER_PROTOCOL');\n    }\n\n    /**\n     * 当前请求 REMOTE_PORT\n     * @access public\n     * @return integer\n     */\n    public function remotePort()\n    {\n        return $this->server('REMOTE_PORT');\n    }\n\n    /**\n     * 当前请求 HTTP_CONTENT_TYPE\n     * @access public\n     * @return string\n     */\n    public function contentType()\n    {\n        $contentType = $this->server('CONTENT_TYPE');\n        if ($contentType) {\n            if (strpos($contentType, ';')) {\n                list($type) = explode(';', $contentType);\n            } else {\n                $type = $contentType;\n            }\n            return trim($type);\n        }\n        return '';\n    }\n\n    /**\n     * 获取当前请求的路由信息\n     * @access public\n     * @param array $route 路由名称\n     * @return array\n     */\n    public function routeInfo($route = [])\n    {\n        if (!empty($route)) {\n            $this->routeInfo = $route;\n        } else {\n            return $this->routeInfo;\n        }\n    }\n\n    /**\n     * 设置或者获取当前请求的调度信息\n     * @access public\n     * @param array  $dispatch 调度信息\n     * @return array\n     */\n    public function dispatch($dispatch = null)\n    {\n        if (!is_null($dispatch)) {\n            $this->dispatch = $dispatch;\n        }\n        return $this->dispatch;\n    }\n\n    /**\n     * 设置或者获取当前的模块名\n     * @access public\n     * @param string $module 模块名\n     * @return string|Request\n     */\n    public function module($module = null)\n    {\n        if (!is_null($module)) {\n            $this->module = $module;\n            return $this;\n        } else {\n            return $this->module ?: '';\n        }\n    }\n\n    /**\n     * 设置或者获取当前的控制器名\n     * @access public\n     * @param string $controller 控制器名\n     * @return string|Request\n     */\n    public function controller($controller = null)\n    {\n        if (!is_null($controller)) {\n            $this->controller = $controller;\n            return $this;\n        } else {\n            return $this->controller ?: '';\n        }\n    }\n\n    /**\n     * 设置或者获取当前的操作名\n     * @access public\n     * @param string $action 操作名\n     * @return string|Request\n     */\n    public function action($action = null)\n    {\n        if (!is_null($action)) {\n            $this->action = $action;\n            return $this;\n        } else {\n            return $this->action ?: '';\n        }\n    }\n\n    /**\n     * 设置或者获取当前的语言\n     * @access public\n     * @param string $lang 语言名\n     * @return string|Request\n     */\n    public function langset($lang = null)\n    {\n        if (!is_null($lang)) {\n            $this->langset = $lang;\n            return $this;\n        } else {\n            return $this->langset ?: '';\n        }\n    }\n\n    /**\n     * 设置或者获取当前请求的content\n     * @access public\n     * @return string\n     */\n    public function getContent()\n    {\n        if (is_null($this->content)) {\n            $this->content = $this->input;\n        }\n        return $this->content;\n    }\n\n    /**\n     * 获取当前请求的php://input\n     * @access public\n     * @return string\n     */\n    public function getInput()\n    {\n        return $this->input;\n    }\n\n    /**\n     * 生成请求令牌\n     * @access public\n     * @param string $name 令牌名称\n     * @param mixed  $type 令牌生成方法\n     * @return string\n     */\n    public function token($name = '__token__', $type = 'md5')\n    {\n        $type  = is_callable($type) ? $type : 'md5';\n        $token = call_user_func($type, $_SERVER['REQUEST_TIME_FLOAT']);\n        if ($this->isAjax()) {\n            header($name . ': ' . $token);\n        }\n        Session::set($name, $token);\n        return $token;\n    }\n\n    /**\n     * 设置当前地址的请求缓存\n     * @access public\n     * @param string $key 缓存标识，支持变量规则 ，例如 item/:name/:id\n     * @param mixed  $expire 缓存有效期\n     * @param array  $except 缓存排除\n     * @return void\n     */\n    public function cache($key, $expire = null, $except = [])\n    {\n        if (false !== $key && $this->isGet() && !$this->isCheckCache) {\n            // 标记请求缓存检查\n            $this->isCheckCache = true;\n            if (false === $expire) {\n                // 关闭当前缓存\n                return;\n            }\n            if ($key instanceof \\Closure) {\n                $key = call_user_func_array($key, [$this]);\n            } elseif (true === $key) {\n                foreach ($except as $rule) {\n                    if (0 === stripos($this->url(), $rule)) {\n                        return;\n                    }\n                }\n                // 自动缓存功能\n                $key = '__URL__';\n            } elseif (strpos($key, '|')) {\n                list($key, $fun) = explode('|', $key);\n            }\n            // 特殊规则替换\n            if (false !== strpos($key, '__')) {\n                $key = str_replace(['__MODULE__', '__CONTROLLER__', '__ACTION__', '__URL__', ''], [$this->module, $this->controller, $this->action, md5($this->url(true))], $key);\n            }\n\n            if (false !== strpos($key, ':')) {\n                $param = $this->param();\n                foreach ($param as $item => $val) {\n                    if (is_string($val) && false !== strpos($key, ':' . $item)) {\n                        $key = str_replace(':' . $item, $val, $key);\n                    }\n                }\n            } elseif (strpos($key, ']')) {\n                if ('[' . $this->ext() . ']' == $key) {\n                    // 缓存某个后缀的请求\n                    $key = md5($this->url());\n                } else {\n                    return;\n                }\n            }\n            if (isset($fun)) {\n                $key = $fun($key);\n            }\n\n            if (strtotime($this->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $_SERVER['REQUEST_TIME']) {\n                // 读取缓存\n                $response = Response::create()->code(304);\n                throw new \\think\\exception\\HttpResponseException($response);\n            } elseif (Cache::has($key)) {\n                list($content, $header) = Cache::get($key);\n                $response               = Response::create($content)->header($header);\n                throw new \\think\\exception\\HttpResponseException($response);\n            } else {\n                $this->cache = [$key, $expire];\n            }\n        }\n    }\n\n    /**\n     * 读取请求缓存设置\n     * @access public\n     * @return array\n     */\n    public function getCache()\n    {\n        return $this->cache;\n    }\n\n    /**\n     * 设置当前请求绑定的对象实例\n     * @access public\n     * @param string $name 绑定的对象标识\n     * @param mixed  $obj 绑定的对象实例\n     * @return mixed\n     */\n    public function bind($name, $obj = null)\n    {\n        if (is_array($name)) {\n            $this->bind = array_merge($this->bind, $name);\n        } else {\n            $this->bind[$name] = $obj;\n        }\n    }\n\n    public function __set($name, $value)\n    {\n        $this->bind[$name] = $value;\n    }\n\n    public function __get($name)\n    {\n        return isset($this->bind[$name]) ? $this->bind[$name] : null;\n    }\n\n    public function __isset($name)\n    {\n        return isset($this->bind[$name]);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Response.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\response\\Json as JsonResponse;\nuse think\\response\\Jsonp as JsonpResponse;\nuse think\\response\\Redirect as RedirectResponse;\nuse think\\response\\View as ViewResponse;\nuse think\\response\\Xml as XmlResponse;\n\nclass Response\n{\n    // 原始数据\n    protected $data;\n\n    // 当前的contentType\n    protected $contentType = 'text/html';\n\n    // 字符集\n    protected $charset = 'utf-8';\n\n    //状态\n    protected $code = 200;\n\n    // 输出参数\n    protected $options = [];\n    // header参数\n    protected $header = [];\n\n    protected $content = null;\n\n    /**\n     * 构造函数\n     * @access   public\n     * @param mixed $data    输出数据\n     * @param int   $code\n     * @param array $header\n     * @param array $options 输出参数\n     */\n    public function __construct($data = '', $code = 200, array $header = [], $options = [])\n    {\n        $this->data($data);\n        if (!empty($options)) {\n            $this->options = array_merge($this->options, $options);\n        }\n        $this->contentType($this->contentType, $this->charset);\n        $this->header = array_merge($this->header, $header);\n        $this->code   = $code;\n    }\n\n    /**\n     * 创建Response对象\n     * @access public\n     * @param mixed  $data    输出数据\n     * @param string $type    输出类型\n     * @param int    $code\n     * @param array  $header\n     * @param array  $options 输出参数\n     * @return Response|JsonResponse|ViewResponse|XmlResponse|RedirectResponse|JsonpResponse\n     */\n    public static function create($data = '', $type = '', $code = 200, array $header = [], $options = [])\n    {\n        $type = empty($type) ? 'null' : strtolower($type);\n\n        $class = false !== strpos($type, '\\\\') ? $type : '\\\\think\\\\response\\\\' . ucfirst($type);\n        if (class_exists($class)) {\n            $response = new $class($data, $code, $header, $options);\n        } else {\n            $response = new static($data, $code, $header, $options);\n        }\n\n        return $response;\n    }\n\n    /**\n     * 发送数据到客户端\n     * @access public\n     * @return mixed\n     * @throws \\InvalidArgumentException\n     */\n    public function send()\n    {\n        // 监听response_send\n        Hook::listen('response_send', $this);\n\n        // 处理输出数据\n        $data = $this->getContent();\n\n        // Trace调试注入\n        if (Env::get('app_trace', Config::get('app_trace'))) {\n            Debug::inject($this, $data);\n        }\n\n        if (200 == $this->code) {\n            $cache = Request::instance()->getCache();\n            if ($cache) {\n                $this->header['Cache-Control'] = 'max-age=' . $cache[1] . ',must-revalidate';\n                $this->header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT';\n                $this->header['Expires']       = gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT';\n                Cache::set($cache[0], [$data, $this->header], $cache[1]);\n            }\n        }\n\n        if (!headers_sent() && !empty($this->header)) {\n            // 发送状态码\n            http_response_code($this->code);\n            // 发送头部信息\n            foreach ($this->header as $name => $val) {\n                if (is_null($val)) {\n                    header($name);\n                } else {\n                    header($name . ':' . $val);\n                }\n            }\n        }\n\n        echo $data;\n\n        if (function_exists('fastcgi_finish_request')) {\n            // 提高页面响应\n            fastcgi_finish_request();\n        }\n\n        // 监听response_end\n        Hook::listen('response_end', $this);\n\n        // 清空当次请求有效的数据\n        if (!($this instanceof RedirectResponse)) {\n            Session::flush();\n        }\n    }\n\n    /**\n     * 处理数据\n     * @access protected\n     * @param mixed $data 要处理的数据\n     * @return mixed\n     */\n    protected function output($data)\n    {\n        return $data;\n    }\n\n    /**\n     * 输出的参数\n     * @access public\n     * @param mixed $options 输出参数\n     * @return $this\n     */\n    public function options($options = [])\n    {\n        $this->options = array_merge($this->options, $options);\n        return $this;\n    }\n\n    /**\n     * 输出数据设置\n     * @access public\n     * @param mixed $data 输出数据\n     * @return $this\n     */\n    public function data($data)\n    {\n        $this->data = $data;\n        return $this;\n    }\n\n    /**\n     * 设置响应头\n     * @access public\n     * @param string|array $name  参数名\n     * @param string       $value 参数值\n     * @return $this\n     */\n    public function header($name, $value = null)\n    {\n        if (is_array($name)) {\n            $this->header = array_merge($this->header, $name);\n        } else {\n            $this->header[$name] = $value;\n        }\n        return $this;\n    }\n\n    /**\n     * 设置页面输出内容\n     * @param $content\n     * @return $this\n     */\n    public function content($content)\n    {\n        if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([\n            $content,\n            '__toString',\n        ])\n        ) {\n            throw new \\InvalidArgumentException(sprintf('variable type error： %s', gettype($content)));\n        }\n\n        $this->content = (string) $content;\n\n        return $this;\n    }\n\n    /**\n     * 发送HTTP状态\n     * @param integer $code 状态码\n     * @return $this\n     */\n    public function code($code)\n    {\n        $this->code = $code;\n        return $this;\n    }\n\n    /**\n     * LastModified\n     * @param string $time\n     * @return $this\n     */\n    public function lastModified($time)\n    {\n        $this->header['Last-Modified'] = $time;\n        return $this;\n    }\n\n    /**\n     * Expires\n     * @param string $time\n     * @return $this\n     */\n    public function expires($time)\n    {\n        $this->header['Expires'] = $time;\n        return $this;\n    }\n\n    /**\n     * ETag\n     * @param string $eTag\n     * @return $this\n     */\n    public function eTag($eTag)\n    {\n        $this->header['ETag'] = $eTag;\n        return $this;\n    }\n\n    /**\n     * 页面缓存控制\n     * @param string $cache 状态码\n     * @return $this\n     */\n    public function cacheControl($cache)\n    {\n        $this->header['Cache-control'] = $cache;\n        return $this;\n    }\n\n    /**\n     * 页面输出类型\n     * @param string $contentType 输出类型\n     * @param string $charset     输出编码\n     * @return $this\n     */\n    public function contentType($contentType, $charset = 'utf-8')\n    {\n        $this->header['Content-Type'] = $contentType . '; charset=' . $charset;\n        return $this;\n    }\n\n    /**\n     * 获取头部信息\n     * @param string $name 头部名称\n     * @return mixed\n     */\n    public function getHeader($name = '')\n    {\n        if (!empty($name)) {\n            return isset($this->header[$name]) ? $this->header[$name] : null;\n        } else {\n            return $this->header;\n        }\n    }\n\n    /**\n     * 获取原始数据\n     * @return mixed\n     */\n    public function getData()\n    {\n        return $this->data;\n    }\n\n    /**\n     * 获取输出数据\n     * @return mixed\n     */\n    public function getContent()\n    {\n        if (null == $this->content) {\n            $content = $this->output($this->data);\n\n            if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([\n                $content,\n                '__toString',\n            ])\n            ) {\n                throw new \\InvalidArgumentException(sprintf('variable type error： %s', gettype($content)));\n            }\n\n            $this->content = (string) $content;\n        }\n        return $this->content;\n    }\n\n    /**\n     * 获取状态码\n     * @return integer\n     */\n    public function getCode()\n    {\n        return $this->code;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Route.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\exception\\HttpException;\n\nclass Route\n{\n    // 路由规则\n    private static $rules = [\n        'get'     => [],\n        'post'    => [],\n        'put'     => [],\n        'delete'  => [],\n        'patch'   => [],\n        'head'    => [],\n        'options' => [],\n        '*'       => [],\n        'alias'   => [],\n        'domain'  => [],\n        'pattern' => [],\n        'name'    => [],\n    ];\n\n    // REST路由操作方法定义\n    private static $rest = [\n        'index'  => ['get', '', 'index'],\n        'create' => ['get', '/create', 'create'],\n        'edit'   => ['get', '/:id/edit', 'edit'],\n        'read'   => ['get', '/:id', 'read'],\n        'save'   => ['post', '', 'save'],\n        'update' => ['put', '/:id', 'update'],\n        'delete' => ['delete', '/:id', 'delete'],\n    ];\n\n    // 不同请求类型的方法前缀\n    private static $methodPrefix = [\n        'get'    => 'get',\n        'post'   => 'post',\n        'put'    => 'put',\n        'delete' => 'delete',\n        'patch'  => 'patch',\n    ];\n\n    // 子域名\n    private static $subDomain = '';\n    // 域名绑定\n    private static $bind = [];\n    // 当前分组信息\n    private static $group = [];\n    // 当前子域名绑定\n    private static $domainBind;\n    private static $domainRule;\n    // 当前域名\n    private static $domain;\n    // 当前路由执行过程中的参数\n    private static $option = [];\n\n    /**\n     * 注册变量规则\n     * @access public\n     * @param string|array  $name 变量名\n     * @param string        $rule 变量规则\n     * @return void\n     */\n    public static function pattern($name = null, $rule = '')\n    {\n        if (is_array($name)) {\n            self::$rules['pattern'] = array_merge(self::$rules['pattern'], $name);\n        } else {\n            self::$rules['pattern'][$name] = $rule;\n        }\n    }\n\n    /**\n     * 注册子域名部署规则\n     * @access public\n     * @param string|array  $domain 子域名\n     * @param mixed         $rule 路由规则\n     * @param array         $option 路由参数\n     * @param array         $pattern 变量规则\n     * @return void\n     */\n    public static function domain($domain, $rule = '', $option = [], $pattern = [])\n    {\n        if (is_array($domain)) {\n            foreach ($domain as $key => $item) {\n                self::domain($key, $item, $option, $pattern);\n            }\n        } elseif ($rule instanceof \\Closure) {\n            // 执行闭包\n            self::setDomain($domain);\n            call_user_func_array($rule, []);\n            self::setDomain(null);\n        } elseif (is_array($rule)) {\n            self::setDomain($domain);\n            self::group('', function () use ($rule) {\n                // 动态注册域名的路由规则\n                self::registerRules($rule);\n            }, $option, $pattern);\n            self::setDomain(null);\n        } else {\n            self::$rules['domain'][$domain]['[bind]'] = [$rule, $option, $pattern];\n        }\n    }\n\n    private static function setDomain($domain)\n    {\n        self::$domain = $domain;\n    }\n\n    /**\n     * 设置路由绑定\n     * @access public\n     * @param mixed     $bind 绑定信息\n     * @param string    $type 绑定类型 默认为module 支持 namespace class controller\n     * @return mixed\n     */\n    public static function bind($bind, $type = 'module')\n    {\n        self::$bind = ['type' => $type, $type => $bind];\n    }\n\n    /**\n     * 设置或者获取路由标识\n     * @access public\n     * @param string|array     $name 路由命名标识 数组表示批量设置\n     * @param array            $value 路由地址及变量信息\n     * @return array\n     */\n    public static function name($name = '', $value = null)\n    {\n        if (is_array($name)) {\n            return self::$rules['name'] = $name;\n        } elseif ('' === $name) {\n            return self::$rules['name'];\n        } elseif (!is_null($value)) {\n            self::$rules['name'][strtolower($name)][] = $value;\n        } else {\n            $name = strtolower($name);\n            return isset(self::$rules['name'][$name]) ? self::$rules['name'][$name] : null;\n        }\n    }\n\n    /**\n     * 读取路由绑定\n     * @access public\n     * @param string    $type 绑定类型\n     * @return mixed\n     */\n    public static function getBind($type)\n    {\n        return isset(self::$bind[$type]) ? self::$bind[$type] : null;\n    }\n\n    /**\n     * 导入配置文件的路由规则\n     * @access public\n     * @param array     $rule 路由规则\n     * @param string    $type 请求类型\n     * @return void\n     */\n    public static function import(array $rule, $type = '*')\n    {\n        // 检查域名部署\n        if (isset($rule['__domain__'])) {\n            self::domain($rule['__domain__']);\n            unset($rule['__domain__']);\n        }\n\n        // 检查变量规则\n        if (isset($rule['__pattern__'])) {\n            self::pattern($rule['__pattern__']);\n            unset($rule['__pattern__']);\n        }\n\n        // 检查路由别名\n        if (isset($rule['__alias__'])) {\n            self::alias($rule['__alias__']);\n            unset($rule['__alias__']);\n        }\n\n        // 检查资源路由\n        if (isset($rule['__rest__'])) {\n            self::resource($rule['__rest__']);\n            unset($rule['__rest__']);\n        }\n\n        self::registerRules($rule, strtolower($type));\n    }\n\n    // 批量注册路由\n    protected static function registerRules($rules, $type = '*')\n    {\n        foreach ($rules as $key => $val) {\n            if (is_numeric($key)) {\n                $key = array_shift($val);\n            }\n            if (empty($val)) {\n                continue;\n            }\n            if (is_string($key) && 0 === strpos($key, '[')) {\n                $key = substr($key, 1, -1);\n                self::group($key, $val);\n            } elseif (is_array($val)) {\n                self::setRule($key, $val[0], $type, $val[1], isset($val[2]) ? $val[2] : []);\n            } else {\n                self::setRule($key, $val, $type);\n            }\n        }\n    }\n\n    /**\n     * 注册路由规则\n     * @access public\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param string    $type 请求类型\n     * @param array     $option 路由参数\n     * @param array     $pattern 变量规则\n     * @return void\n     */\n    public static function rule($rule, $route = '', $type = '*', $option = [], $pattern = [])\n    {\n        $group = self::getGroup('name');\n\n        if (!is_null($group)) {\n            // 路由分组\n            $option  = array_merge(self::getGroup('option'), $option);\n            $pattern = array_merge(self::getGroup('pattern'), $pattern);\n        }\n\n        $type = strtolower($type);\n\n        if (strpos($type, '|')) {\n            $option['method'] = $type;\n            $type             = '*';\n        }\n        if (is_array($rule) && empty($route)) {\n            foreach ($rule as $key => $val) {\n                if (is_numeric($key)) {\n                    $key = array_shift($val);\n                }\n                if (is_array($val)) {\n                    $route    = $val[0];\n                    $option1  = array_merge($option, $val[1]);\n                    $pattern1 = array_merge($pattern, isset($val[2]) ? $val[2] : []);\n                } else {\n                    $route = $val;\n                }\n                self::setRule($key, $route, $type, isset($option1) ? $option1 : $option, isset($pattern1) ? $pattern1 : $pattern, $group);\n            }\n        } else {\n            self::setRule($rule, $route, $type, $option, $pattern, $group);\n        }\n\n    }\n\n    /**\n     * 设置路由规则\n     * @access public\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param string    $type 请求类型\n     * @param array     $option 路由参数\n     * @param array     $pattern 变量规则\n     * @param string    $group 所属分组\n     * @return void\n     */\n    protected static function setRule($rule, $route, $type = '*', $option = [], $pattern = [], $group = '')\n    {\n        if (is_array($rule)) {\n            $name = $rule[0];\n            $rule = $rule[1];\n        } elseif (is_string($route)) {\n            $name = $route;\n        }\n        if (!isset($option['complete_match'])) {\n            if (Config::get('route_complete_match')) {\n                $option['complete_match'] = true;\n            } elseif ('$' == substr($rule, -1, 1)) {\n                // 是否完整匹配\n                $option['complete_match'] = true;\n            }\n        } elseif (empty($option['complete_match']) && '$' == substr($rule, -1, 1)) {\n            // 是否完整匹配\n            $option['complete_match'] = true;\n        }\n\n        if ('$' == substr($rule, -1, 1)) {\n            $rule = substr($rule, 0, -1);\n        }\n\n        if ('/' != $rule || $group) {\n            $rule = trim($rule, '/');\n        }\n        $vars = self::parseVar($rule);\n        if (isset($name)) {\n            $key    = $group ? $group . ($rule ? '/' . $rule : '') : $rule;\n            $suffix = isset($option['ext']) ? $option['ext'] : null;\n            self::name($name, [$key, $vars, self::$domain, $suffix]);\n        }\n        if (isset($option['modular'])) {\n            $route = $option['modular'] . '/' . $route;\n        }\n        if ($group) {\n            if ('*' != $type) {\n                $option['method'] = $type;\n            }\n            if (self::$domain) {\n                self::$rules['domain'][self::$domain]['*'][$group]['rule'][] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern];\n            } else {\n                self::$rules['*'][$group]['rule'][] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern];\n            }\n        } else {\n            if ('*' != $type && isset(self::$rules['*'][$rule])) {\n                unset(self::$rules['*'][$rule]);\n            }\n            if (self::$domain) {\n                self::$rules['domain'][self::$domain][$type][$rule] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern];\n            } else {\n                self::$rules[$type][$rule] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern];\n            }\n            if ('*' == $type) {\n                // 注册路由快捷方式\n                foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) {\n                    if (self::$domain) {\n                        self::$rules['domain'][self::$domain][$method][$rule] = true;\n                    } else {\n                        self::$rules[$method][$rule] = true;\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 设置当前执行的参数信息\n     * @access public\n     * @param array    $options 参数信息\n     * @return mixed\n     */\n    protected static function setOption($options = [])\n    {\n        self::$option[] = $options;\n    }\n\n    /**\n     * 获取当前执行的所有参数信息\n     * @access public\n     * @return array\n     */\n    public static function getOption()\n    {\n        return self::$option;\n    }\n\n    /**\n     * 获取当前的分组信息\n     * @access public\n     * @param string    $type 分组信息名称 name option pattern\n     * @return mixed\n     */\n    public static function getGroup($type)\n    {\n        if (isset(self::$group[$type])) {\n            return self::$group[$type];\n        } else {\n            return 'name' == $type ? null : [];\n        }\n    }\n\n    /**\n     * 设置当前的路由分组\n     * @access public\n     * @param string    $name 分组名称\n     * @param array     $option 分组路由参数\n     * @param array     $pattern 分组变量规则\n     * @return void\n     */\n    public static function setGroup($name, $option = [], $pattern = [])\n    {\n        self::$group['name']    = $name;\n        self::$group['option']  = $option ?: [];\n        self::$group['pattern'] = $pattern ?: [];\n    }\n\n    /**\n     * 注册路由分组\n     * @access public\n     * @param string|array      $name 分组名称或者参数\n     * @param array|\\Closure    $routes 路由地址\n     * @param array             $option 路由参数\n     * @param array             $pattern 变量规则\n     * @return void\n     */\n    public static function group($name, $routes, $option = [], $pattern = [])\n    {\n        if (is_array($name)) {\n            $option = $name;\n            $name   = isset($option['name']) ? $option['name'] : '';\n        }\n        // 分组\n        $currentGroup = self::getGroup('name');\n        if ($currentGroup) {\n            $name = $currentGroup . ($name ? '/' . ltrim($name, '/') : '');\n        }\n        if (!empty($name)) {\n            if ($routes instanceof \\Closure) {\n                $currentOption  = self::getGroup('option');\n                $currentPattern = self::getGroup('pattern');\n                self::setGroup($name, array_merge($currentOption, $option), array_merge($currentPattern, $pattern));\n                call_user_func_array($routes, []);\n                self::setGroup($currentGroup, $currentOption, $currentPattern);\n                if ($currentGroup != $name) {\n                    self::$rules['*'][$name]['route']   = '';\n                    self::$rules['*'][$name]['var']     = self::parseVar($name);\n                    self::$rules['*'][$name]['option']  = $option;\n                    self::$rules['*'][$name]['pattern'] = $pattern;\n                }\n            } else {\n                $item = [];\n                foreach ($routes as $key => $val) {\n                    if (is_numeric($key)) {\n                        $key = array_shift($val);\n                    }\n                    if (is_array($val)) {\n                        $route    = $val[0];\n                        $option1  = array_merge($option, isset($val[1]) ? $val[1] : []);\n                        $pattern1 = array_merge($pattern, isset($val[2]) ? $val[2] : []);\n                    } else {\n                        $route = $val;\n                    }\n\n                    $options  = isset($option1) ? $option1 : $option;\n                    $patterns = isset($pattern1) ? $pattern1 : $pattern;\n                    if ('$' == substr($key, -1, 1)) {\n                        // 是否完整匹配\n                        $options['complete_match'] = true;\n                        $key                       = substr($key, 0, -1);\n                    }\n                    $key    = trim($key, '/');\n                    $vars   = self::parseVar($key);\n                    $item[] = ['rule' => $key, 'route' => $route, 'var' => $vars, 'option' => $options, 'pattern' => $patterns];\n                    // 设置路由标识\n                    $suffix = isset($options['ext']) ? $options['ext'] : null;\n                    self::name($route, [$name . ($key ? '/' . $key : ''), $vars, self::$domain, $suffix]);\n                }\n                self::$rules['*'][$name] = ['rule' => $item, 'route' => '', 'var' => [], 'option' => $option, 'pattern' => $pattern];\n            }\n\n            foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) {\n                if (!isset(self::$rules[$method][$name])) {\n                    self::$rules[$method][$name] = true;\n                } elseif (is_array(self::$rules[$method][$name])) {\n                    self::$rules[$method][$name] = array_merge(self::$rules['*'][$name], self::$rules[$method][$name]);\n                }\n            }\n\n        } elseif ($routes instanceof \\Closure) {\n            // 闭包注册\n            $currentOption  = self::getGroup('option');\n            $currentPattern = self::getGroup('pattern');\n            self::setGroup('', array_merge($currentOption, $option), array_merge($currentPattern, $pattern));\n            call_user_func_array($routes, []);\n            self::setGroup($currentGroup, $currentOption, $currentPattern);\n        } else {\n            // 批量注册路由\n            self::rule($routes, '', '*', $option, $pattern);\n        }\n    }\n\n    /**\n     * 注册路由\n     * @access public\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param array     $option 路由参数\n     * @param array     $pattern 变量规则\n     * @return void\n     */\n    public static function any($rule, $route = '', $option = [], $pattern = [])\n    {\n        self::rule($rule, $route, '*', $option, $pattern);\n    }\n\n    /**\n     * 注册GET路由\n     * @access public\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param array     $option 路由参数\n     * @param array     $pattern 变量规则\n     * @return void\n     */\n    public static function get($rule, $route = '', $option = [], $pattern = [])\n    {\n        self::rule($rule, $route, 'GET', $option, $pattern);\n    }\n\n    /**\n     * 注册POST路由\n     * @access public\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param array     $option 路由参数\n     * @param array     $pattern 变量规则\n     * @return void\n     */\n    public static function post($rule, $route = '', $option = [], $pattern = [])\n    {\n        self::rule($rule, $route, 'POST', $option, $pattern);\n    }\n\n    /**\n     * 注册PUT路由\n     * @access public\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param array     $option 路由参数\n     * @param array     $pattern 变量规则\n     * @return void\n     */\n    public static function put($rule, $route = '', $option = [], $pattern = [])\n    {\n        self::rule($rule, $route, 'PUT', $option, $pattern);\n    }\n\n    /**\n     * 注册DELETE路由\n     * @access public\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param array     $option 路由参数\n     * @param array     $pattern 变量规则\n     * @return void\n     */\n    public static function delete($rule, $route = '', $option = [], $pattern = [])\n    {\n        self::rule($rule, $route, 'DELETE', $option, $pattern);\n    }\n\n    /**\n     * 注册PATCH路由\n     * @access public\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param array     $option 路由参数\n     * @param array     $pattern 变量规则\n     * @return void\n     */\n    public static function patch($rule, $route = '', $option = [], $pattern = [])\n    {\n        self::rule($rule, $route, 'PATCH', $option, $pattern);\n    }\n\n    /**\n     * 注册资源路由\n     * @access public\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param array     $option 路由参数\n     * @param array     $pattern 变量规则\n     * @return void\n     */\n    public static function resource($rule, $route = '', $option = [], $pattern = [])\n    {\n        if (is_array($rule)) {\n            foreach ($rule as $key => $val) {\n                if (is_array($val)) {\n                    list($val, $option, $pattern) = array_pad($val, 3, []);\n                }\n                self::resource($key, $val, $option, $pattern);\n            }\n        } else {\n            if (strpos($rule, '.')) {\n                // 注册嵌套资源路由\n                $array = explode('.', $rule);\n                $last  = array_pop($array);\n                $item  = [];\n                foreach ($array as $val) {\n                    $item[] = $val . '/:' . (isset($option['var'][$val]) ? $option['var'][$val] : $val . '_id');\n                }\n                $rule = implode('/', $item) . '/' . $last;\n            }\n            // 注册资源路由\n            foreach (self::$rest as $key => $val) {\n                if ((isset($option['only']) && !in_array($key, $option['only']))\n                    || (isset($option['except']) && in_array($key, $option['except']))) {\n                    continue;\n                }\n                if (isset($last) && strpos($val[1], ':id') && isset($option['var'][$last])) {\n                    $val[1] = str_replace(':id', ':' . $option['var'][$last], $val[1]);\n                } elseif (strpos($val[1], ':id') && isset($option['var'][$rule])) {\n                    $val[1] = str_replace(':id', ':' . $option['var'][$rule], $val[1]);\n                }\n                $item           = ltrim($rule . $val[1], '/');\n                $option['rest'] = $key;\n                self::rule($item . '$', $route . '/' . $val[2], $val[0], $option, $pattern);\n            }\n        }\n    }\n\n    /**\n     * 注册控制器路由 操作方法对应不同的请求后缀\n     * @access public\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param array     $option 路由参数\n     * @param array     $pattern 变量规则\n     * @return void\n     */\n    public static function controller($rule, $route = '', $option = [], $pattern = [])\n    {\n        foreach (self::$methodPrefix as $type => $val) {\n            self::$type($rule . '/:action', $route . '/' . $val . ':action', $option, $pattern);\n        }\n    }\n\n    /**\n     * 注册别名路由\n     * @access public\n     * @param string|array  $rule 路由别名\n     * @param string        $route 路由地址\n     * @param array         $option 路由参数\n     * @return void\n     */\n    public static function alias($rule = null, $route = '', $option = [])\n    {\n        if (is_array($rule)) {\n            self::$rules['alias'] = array_merge(self::$rules['alias'], $rule);\n        } else {\n            self::$rules['alias'][$rule] = $option ? [$route, $option] : $route;\n        }\n    }\n\n    /**\n     * 设置不同请求类型下面的方法前缀\n     * @access public\n     * @param string    $method 请求类型\n     * @param string    $prefix 类型前缀\n     * @return void\n     */\n    public static function setMethodPrefix($method, $prefix = '')\n    {\n        if (is_array($method)) {\n            self::$methodPrefix = array_merge(self::$methodPrefix, array_change_key_case($method));\n        } else {\n            self::$methodPrefix[strtolower($method)] = $prefix;\n        }\n    }\n\n    /**\n     * rest方法定义和修改\n     * @access public\n     * @param string        $name 方法名称\n     * @param array|bool    $resource 资源\n     * @return void\n     */\n    public static function rest($name, $resource = [])\n    {\n        if (is_array($name)) {\n            self::$rest = $resource ? $name : array_merge(self::$rest, $name);\n        } else {\n            self::$rest[$name] = $resource;\n        }\n    }\n\n    /**\n     * 注册未匹配路由规则后的处理\n     * @access public\n     * @param string    $route 路由地址\n     * @param string    $method 请求类型\n     * @param array     $option 路由参数\n     * @return void\n     */\n    public static function miss($route, $method = '*', $option = [])\n    {\n        self::rule('__miss__', $route, $method, $option, []);\n    }\n\n    /**\n     * 注册一个自动解析的URL路由\n     * @access public\n     * @param string    $route 路由地址\n     * @return void\n     */\n    public static function auto($route)\n    {\n        self::rule('__auto__', $route, '*', [], []);\n    }\n\n    /**\n     * 获取或者批量设置路由定义\n     * @access public\n     * @param mixed $rules 请求类型或者路由定义数组\n     * @return array\n     */\n    public static function rules($rules = '')\n    {\n        if (is_array($rules)) {\n            self::$rules = $rules;\n        } elseif ($rules) {\n            return true === $rules ? self::$rules : self::$rules[strtolower($rules)];\n        } else {\n            $rules = self::$rules;\n            unset($rules['pattern'], $rules['alias'], $rules['domain'], $rules['name']);\n            return $rules;\n        }\n    }\n\n    /**\n     * 检测子域名部署\n     * @access public\n     * @param Request   $request Request请求对象\n     * @param array     $currentRules 当前路由规则\n     * @param string    $method 请求类型\n     * @return void\n     */\n    public static function checkDomain($request, &$currentRules, $method = 'get')\n    {\n        // 域名规则\n        $rules = self::$rules['domain'];\n        // 开启子域名部署 支持二级和三级域名\n        if (!empty($rules)) {\n            $host = $request->host();\n            if (isset($rules[$host])) {\n                // 完整域名或者IP配置\n                $item = $rules[$host];\n            } else {\n                $rootDomain = Config::get('url_domain_root');\n                if ($rootDomain) {\n                    // 配置域名根 例如 thinkphp.cn 163.com.cn 如果是国家级域名 com.cn net.cn 之类的域名需要配置\n                    $domain = explode('.', rtrim(stristr($host, $rootDomain, true), '.'));\n                } else {\n                    $domain = explode('.', $host, -2);\n                }\n                // 子域名配置\n                if (!empty($domain)) {\n                    // 当前子域名\n                    $subDomain       = implode('.', $domain);\n                    self::$subDomain = $subDomain;\n                    $domain2         = array_pop($domain);\n                    if ($domain) {\n                        // 存在三级域名\n                        $domain3 = array_pop($domain);\n                    }\n                    if ($subDomain && isset($rules[$subDomain])) {\n                        // 子域名配置\n                        $item = $rules[$subDomain];\n                    } elseif (isset($rules['*.' . $domain2]) && !empty($domain3)) {\n                        // 泛三级域名\n                        $item      = $rules['*.' . $domain2];\n                        $panDomain = $domain3;\n                    } elseif (isset($rules['*']) && !empty($domain2)) {\n                        // 泛二级域名\n                        if ('www' != $domain2) {\n                            $item      = $rules['*'];\n                            $panDomain = $domain2;\n                        }\n                    }\n                }\n            }\n            if (!empty($item)) {\n                if (isset($panDomain)) {\n                    // 保存当前泛域名\n                    $request->route(['__domain__' => $panDomain]);\n                }\n                if (isset($item['[bind]'])) {\n                    // 解析子域名部署规则\n                    list($rule, $option, $pattern) = $item['[bind]'];\n                    if (!empty($option['https']) && !$request->isSsl()) {\n                        // https检测\n                        throw new HttpException(404, 'must use https request:' . $host);\n                    }\n\n                    if (strpos($rule, '?')) {\n                        // 传入其它参数\n                        $array  = parse_url($rule);\n                        $result = $array['path'];\n                        parse_str($array['query'], $params);\n                        if (isset($panDomain)) {\n                            $pos = array_search('*', $params);\n                            if (false !== $pos) {\n                                // 泛域名作为参数\n                                $params[$pos] = $panDomain;\n                            }\n                        }\n                        $_GET = array_merge($_GET, $params);\n                    } else {\n                        $result = $rule;\n                    }\n\n                    if (0 === strpos($result, '\\\\')) {\n                        // 绑定到命名空间 例如 \\app\\index\\behavior\n                        self::$bind = ['type' => 'namespace', 'namespace' => $result];\n                    } elseif (0 === strpos($result, '@')) {\n                        // 绑定到类 例如 @app\\index\\controller\\User\n                        self::$bind = ['type' => 'class', 'class' => substr($result, 1)];\n                    } else {\n                        // 绑定到模块/控制器 例如 index/user\n                        self::$bind = ['type' => 'module', 'module' => $result];\n                    }\n                    self::$domainBind = true;\n                } else {\n                    self::$domainRule = $item;\n                    $currentRules     = isset($item[$method]) ? $item[$method] : $item['*'];\n                }\n            }\n        }\n    }\n\n    /**\n     * 检测URL路由\n     * @access public\n     * @param Request   $request Request请求对象\n     * @param string    $url URL地址\n     * @param string    $depr URL分隔符\n     * @param bool      $checkDomain 是否检测域名规则\n     * @return false|array\n     */\n    public static function check($request, $url, $depr = '/', $checkDomain = false)\n    {\n        // 分隔符替换 确保路由定义使用统一的分隔符\n        $url = str_replace($depr, '|', $url);\n\n        if (isset(self::$rules['alias'][$url]) || isset(self::$rules['alias'][strstr($url, '|', true)])) {\n            // 检测路由别名\n            $result = self::checkRouteAlias($request, $url, $depr);\n            if (false !== $result) {\n                return $result;\n            }\n        }\n        $method = strtolower($request->method());\n        // 获取当前请求类型的路由规则\n        $rules = isset(self::$rules[$method]) ? self::$rules[$method] : [];\n        // 检测域名部署\n        if ($checkDomain) {\n            self::checkDomain($request, $rules, $method);\n        }\n        // 检测URL绑定\n        $return = self::checkUrlBind($url, $rules, $depr);\n        if (false !== $return) {\n            return $return;\n        }\n        if ('|' != $url) {\n            $url = rtrim($url, '|');\n        }\n        $item = str_replace('|', '/', $url);\n        if (isset($rules[$item])) {\n            // 静态路由规则检测\n            $rule = $rules[$item];\n            if (true === $rule) {\n                $rule = self::getRouteExpress($item);\n            }\n            if (!empty($rule['route']) && self::checkOption($rule['option'], $request)) {\n                self::setOption($rule['option']);\n                return self::parseRule($item, $rule['route'], $url, $rule['option']);\n            }\n        }\n\n        // 路由规则检测\n        if (!empty($rules)) {\n            return self::checkRoute($request, $rules, $url, $depr);\n        }\n        return false;\n    }\n\n    private static function getRouteExpress($key)\n    {\n        return self::$domainRule ? self::$domainRule['*'][$key] : self::$rules['*'][$key];\n    }\n\n    /**\n     * 检测路由规则\n     * @access private\n     * @param Request   $request\n     * @param array     $rules 路由规则\n     * @param string    $url URL地址\n     * @param string    $depr URL分割符\n     * @param string    $group 路由分组名\n     * @param array     $options 路由参数（分组）\n     * @return mixed\n     */\n    private static function checkRoute($request, $rules, $url, $depr = '/', $group = '', $options = [])\n    {\n        foreach ($rules as $key => $item) {\n            if (true === $item) {\n                $item = self::getRouteExpress($key);\n            }\n            if (!isset($item['rule'])) {\n                continue;\n            }\n            $rule    = $item['rule'];\n            $route   = $item['route'];\n            $vars    = $item['var'];\n            $option  = $item['option'];\n            $pattern = $item['pattern'];\n\n            // 检查参数有效性\n            if (!self::checkOption($option, $request)) {\n                continue;\n            }\n\n            if (isset($option['ext'])) {\n                // 路由ext参数 优先于系统配置的URL伪静态后缀参数\n                $url = preg_replace('/\\.' . $request->ext() . '$/i', '', $url);\n            }\n\n            if (is_array($rule)) {\n                // 分组路由\n                $pos = strpos(str_replace('<', ':', $key), ':');\n                if (false !== $pos) {\n                    $str = substr($key, 0, $pos);\n                } else {\n                    $str = $key;\n                }\n                if (is_string($str) && $str && 0 !== stripos(str_replace('|', '/', $url), $str)) {\n                    continue;\n                }\n                self::setOption($option);\n                $result = self::checkRoute($request, $rule, $url, $depr, $key, $option);\n                if (false !== $result) {\n                    return $result;\n                }\n            } elseif ($route) {\n                if ('__miss__' == $rule || '__auto__' == $rule) {\n                    // 指定特殊路由\n                    $var    = trim($rule, '__');\n                    ${$var} = $item;\n                    continue;\n                }\n                if ($group) {\n                    $rule = $group . ($rule ? '/' . ltrim($rule, '/') : '');\n                }\n\n                self::setOption($option);\n                if (isset($options['bind_model']) && isset($option['bind_model'])) {\n                    $option['bind_model'] = array_merge($options['bind_model'], $option['bind_model']);\n                }\n                $result = self::checkRule($rule, $route, $url, $pattern, $option, $depr);\n                if (false !== $result) {\n                    return $result;\n                }\n            }\n        }\n        if (isset($auto)) {\n            // 自动解析URL地址\n            return self::parseUrl($auto['route'] . '/' . $url, $depr);\n        } elseif (isset($miss)) {\n            // 未匹配所有路由的路由规则处理\n            return self::parseRule('', $miss['route'], $url, $miss['option']);\n        }\n        return false;\n    }\n\n    /**\n     * 检测路由别名\n     * @access private\n     * @param Request   $request\n     * @param string    $url URL地址\n     * @param string    $depr URL分隔符\n     * @return mixed\n     */\n    private static function checkRouteAlias($request, $url, $depr)\n    {\n        $array = explode('|', $url);\n        $alias = array_shift($array);\n        $item  = self::$rules['alias'][$alias];\n\n        if (is_array($item)) {\n            list($rule, $option) = $item;\n            $action              = $array[0];\n            if (isset($option['allow']) && !in_array($action, explode(',', $option['allow']))) {\n                // 允许操作\n                return false;\n            } elseif (isset($option['except']) && in_array($action, explode(',', $option['except']))) {\n                // 排除操作\n                return false;\n            }\n            if (isset($option['method'][$action])) {\n                $option['method'] = $option['method'][$action];\n            }\n        } else {\n            $rule = $item;\n        }\n        $bind = implode('|', $array);\n        // 参数有效性检查\n        if (isset($option) && !self::checkOption($option, $request)) {\n            // 路由不匹配\n            return false;\n        } elseif (0 === strpos($rule, '\\\\')) {\n            // 路由到类\n            return self::bindToClass($bind, substr($rule, 1), $depr);\n        } elseif (0 === strpos($rule, '@')) {\n            // 路由到控制器类\n            return self::bindToController($bind, substr($rule, 1), $depr);\n        } else {\n            // 路由到模块/控制器\n            return self::bindToModule($bind, $rule, $depr);\n        }\n    }\n\n    /**\n     * 检测URL绑定\n     * @access private\n     * @param string    $url URL地址\n     * @param array     $rules 路由规则\n     * @param string    $depr URL分隔符\n     * @return mixed\n     */\n    private static function checkUrlBind(&$url, &$rules, $depr = '/')\n    {\n        if (!empty(self::$bind)) {\n            $type = self::$bind['type'];\n            $bind = self::$bind[$type];\n            // 记录绑定信息\n            App::$debug && Log::record('[ BIND ] ' . var_export($bind, true), 'info');\n            // 如果有URL绑定 则进行绑定检测\n            switch ($type) {\n                case 'class':\n                    // 绑定到类\n                    return self::bindToClass($url, $bind, $depr);\n                case 'controller':\n                    // 绑定到控制器类\n                    return self::bindToController($url, $bind, $depr);\n                case 'namespace':\n                    // 绑定到命名空间\n                    return self::bindToNamespace($url, $bind, $depr);\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 绑定到类\n     * @access public\n     * @param string    $url URL地址\n     * @param string    $class 类名（带命名空间）\n     * @param string    $depr URL分隔符\n     * @return array\n     */\n    public static function bindToClass($url, $class, $depr = '/')\n    {\n        $url    = str_replace($depr, '|', $url);\n        $array  = explode('|', $url, 2);\n        $action = !empty($array[0]) ? $array[0] : Config::get('default_action');\n        if (!empty($array[1])) {\n            self::parseUrlParams($array[1]);\n        }\n        return ['type' => 'method', 'method' => [$class, $action], 'var' => []];\n    }\n\n    /**\n     * 绑定到命名空间\n     * @access public\n     * @param string    $url URL地址\n     * @param string    $namespace 命名空间\n     * @param string    $depr URL分隔符\n     * @return array\n     */\n    public static function bindToNamespace($url, $namespace, $depr = '/')\n    {\n        $url    = str_replace($depr, '|', $url);\n        $array  = explode('|', $url, 3);\n        $class  = !empty($array[0]) ? $array[0] : Config::get('default_controller');\n        $method = !empty($array[1]) ? $array[1] : Config::get('default_action');\n        if (!empty($array[2])) {\n            self::parseUrlParams($array[2]);\n        }\n        return ['type' => 'method', 'method' => [$namespace . '\\\\' . Loader::parseName($class, 1), $method], 'var' => []];\n    }\n\n    /**\n     * 绑定到控制器类\n     * @access public\n     * @param string    $url URL地址\n     * @param string    $controller 控制器名 （支持带模块名 index/user ）\n     * @param string    $depr URL分隔符\n     * @return array\n     */\n    public static function bindToController($url, $controller, $depr = '/')\n    {\n        $url    = str_replace($depr, '|', $url);\n        $array  = explode('|', $url, 2);\n        $action = !empty($array[0]) ? $array[0] : Config::get('default_action');\n        if (!empty($array[1])) {\n            self::parseUrlParams($array[1]);\n        }\n        return ['type' => 'controller', 'controller' => $controller . '/' . $action, 'var' => []];\n    }\n\n    /**\n     * 绑定到模块/控制器\n     * @access public\n     * @param string    $url URL地址\n     * @param string    $controller 控制器类名（带命名空间）\n     * @param string    $depr URL分隔符\n     * @return array\n     */\n    public static function bindToModule($url, $controller, $depr = '/')\n    {\n        $url    = str_replace($depr, '|', $url);\n        $array  = explode('|', $url, 2);\n        $action = !empty($array[0]) ? $array[0] : Config::get('default_action');\n        if (!empty($array[1])) {\n            self::parseUrlParams($array[1]);\n        }\n        return ['type' => 'module', 'module' => $controller . '/' . $action];\n    }\n\n    /**\n     * 路由参数有效性检查\n     * @access private\n     * @param array     $option 路由参数\n     * @param Request   $request Request对象\n     * @return bool\n     */\n    private static function checkOption($option, $request)\n    {\n        if ((isset($option['method']) && is_string($option['method']) && false === stripos($option['method'], $request->method()))\n            || (isset($option['ajax']) && $option['ajax'] && !$request->isAjax()) // Ajax检测\n             || (isset($option['ajax']) && !$option['ajax'] && $request->isAjax()) // 非Ajax检测\n             || (isset($option['pjax']) && $option['pjax'] && !$request->isPjax()) // Pjax检测\n             || (isset($option['pjax']) && !$option['pjax'] && $request->isPjax()) // 非Pjax检测\n             || (isset($option['ext']) && false === stripos('|' . $option['ext'] . '|', '|' . $request->ext() . '|')) // 伪静态后缀检测\n             || (isset($option['deny_ext']) && false !== stripos('|' . $option['deny_ext'] . '|', '|' . $request->ext() . '|'))\n            || (isset($option['domain']) && !in_array($option['domain'], [$_SERVER['HTTP_HOST'], self::$subDomain])) // 域名检测\n             || (isset($option['https']) && $option['https'] && !$request->isSsl()) // https检测\n             || (isset($option['https']) && !$option['https'] && $request->isSsl()) // https检测\n             || (!empty($option['before_behavior']) && false === Hook::exec($option['before_behavior'])) // 行为检测\n             || (!empty($option['callback']) && is_callable($option['callback']) && false === call_user_func($option['callback'])) // 自定义检测\n        ) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 检测路由规则\n     * @access private\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param string    $url URL地址\n     * @param array     $pattern 变量规则\n     * @param array     $option 路由参数\n     * @param string    $depr URL分隔符（全局）\n     * @return array|false\n     */\n    private static function checkRule($rule, $route, $url, $pattern, $option, $depr)\n    {\n        // 检查完整规则定义\n        if (isset($pattern['__url__']) && !preg_match(0 === strpos($pattern['__url__'], '/') ? $pattern['__url__'] : '/^' . $pattern['__url__'] . '/', str_replace('|', $depr, $url))) {\n            return false;\n        }\n        // 检查路由的参数分隔符\n        if (isset($option['param_depr'])) {\n            $url = str_replace(['|', $option['param_depr']], [$depr, '|'], $url);\n        }\n\n        $len1 = substr_count($url, '|');\n        $len2 = substr_count($rule, '/');\n        // 多余参数是否合并\n        $merge = !empty($option['merge_extra_vars']);\n        if ($merge && $len1 > $len2) {\n            $url = str_replace('|', $depr, $url);\n            $url = implode('|', explode($depr, $url, $len2 + 1));\n        }\n\n        if ($len1 >= $len2 || strpos($rule, '[')) {\n            if (!empty($option['complete_match'])) {\n                // 完整匹配\n                if (!$merge && $len1 != $len2 && (false === strpos($rule, '[') || $len1 > $len2 || $len1 < $len2 - substr_count($rule, '['))) {\n                    return false;\n                }\n            }\n            $pattern = array_merge(self::$rules['pattern'], $pattern);\n            if (false !== $match = self::match($url, $rule, $pattern)) {\n                // 匹配到路由规则\n                return self::parseRule($rule, $route, $url, $option, $match);\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 解析模块的URL地址 [模块/控制器/操作?]参数1=值1&参数2=值2...\n     * @access public\n     * @param string    $url URL地址\n     * @param string    $depr URL分隔符\n     * @param bool      $autoSearch 是否自动深度搜索控制器\n     * @return array\n     */\n    public static function parseUrl($url, $depr = '/', $autoSearch = false)\n    {\n\n        if (isset(self::$bind['module'])) {\n            $bind = str_replace('/', $depr, self::$bind['module']);\n            // 如果有模块/控制器绑定\n            $url = $bind . ('.' != substr($bind, -1) ? $depr : '') . ltrim($url, $depr);\n        }\n        $url              = str_replace($depr, '|', $url);\n        list($path, $var) = self::parseUrlPath($url);\n        $route            = [null, null, null];\n        if (isset($path)) {\n            // 解析模块\n            $module = Config::get('app_multi_module') ? array_shift($path) : null;\n            if ($autoSearch) {\n                // 自动搜索控制器\n                $dir    = APP_PATH . ($module ? $module . DS : '') . Config::get('url_controller_layer');\n                $suffix = App::$suffix || Config::get('controller_suffix') ? ucfirst(Config::get('url_controller_layer')) : '';\n                $item   = [];\n                $find   = false;\n                foreach ($path as $val) {\n                    $item[] = $val;\n                    $file   = $dir . DS . str_replace('.', DS, $val) . $suffix . EXT;\n                    $file   = pathinfo($file, PATHINFO_DIRNAME) . DS . Loader::parseName(pathinfo($file, PATHINFO_FILENAME), 1) . EXT;\n                    if (is_file($file)) {\n                        $find = true;\n                        break;\n                    } else {\n                        $dir .= DS . Loader::parseName($val);\n                    }\n                }\n                if ($find) {\n                    $controller = implode('.', $item);\n                    $path       = array_slice($path, count($item));\n                } else {\n                    $controller = array_shift($path);\n                }\n            } else {\n                // 解析控制器\n                $controller = !empty($path) ? array_shift($path) : null;\n            }\n            // 解析操作\n            $action = !empty($path) ? array_shift($path) : null;\n            // 解析额外参数\n            self::parseUrlParams(empty($path) ? '' : implode('|', $path));\n            // 封装路由\n            $route = [$module, $controller, $action];\n            // 检查地址是否被定义过路由\n            $name  = strtolower($module . '/' . Loader::parseName($controller, 1) . '/' . $action);\n            $name2 = '';\n            if (empty($module) || isset($bind) && $module == $bind) {\n                $name2 = strtolower(Loader::parseName($controller, 1) . '/' . $action);\n            }\n\n            if (isset(self::$rules['name'][$name]) || isset(self::$rules['name'][$name2])) {\n                throw new HttpException(404, 'invalid request:' . str_replace('|', $depr, $url));\n            }\n        }\n        return ['type' => 'module', 'module' => $route];\n    }\n\n    /**\n     * 解析URL的pathinfo参数和变量\n     * @access private\n     * @param string    $url URL地址\n     * @return array\n     */\n    private static function parseUrlPath($url)\n    {\n        // 分隔符替换 确保路由定义使用统一的分隔符\n        $url = str_replace('|', '/', $url);\n        $url = trim($url, '/');\n        $var = [];\n        if (false !== strpos($url, '?')) {\n            // [模块/控制器/操作?]参数1=值1&参数2=值2...\n            $info = parse_url($url);\n            $path = explode('/', $info['path']);\n            parse_str($info['query'], $var);\n        } elseif (strpos($url, '/')) {\n            // [模块/控制器/操作]\n            $path = explode('/', $url);\n        } else {\n            $path = [$url];\n        }\n        return [$path, $var];\n    }\n\n    /**\n     * 检测URL和规则路由是否匹配\n     * @access private\n     * @param string    $url URL地址\n     * @param string    $rule 路由规则\n     * @param array     $pattern 变量规则\n     * @return array|false\n     */\n    private static function match($url, $rule, $pattern)\n    {\n        $m2 = explode('/', $rule);\n        $m1 = explode('|', $url);\n\n        $var = [];\n        foreach ($m2 as $key => $val) {\n            // val中定义了多个变量 <id><name>\n            if (false !== strpos($val, '<') && preg_match_all('/<(\\w+(\\??))>/', $val, $matches)) {\n                $value   = [];\n                $replace = [];\n                foreach ($matches[1] as $name) {\n                    if (strpos($name, '?')) {\n                        $name      = substr($name, 0, -1);\n                        $replace[] = '(' . (isset($pattern[$name]) ? $pattern[$name] : '\\w+') . ')?';\n                    } else {\n                        $replace[] = '(' . (isset($pattern[$name]) ? $pattern[$name] : '\\w+') . ')';\n                    }\n                    $value[] = $name;\n                }\n                $val = str_replace($matches[0], $replace, $val);\n                if (preg_match('/^' . $val . '$/', isset($m1[$key]) ? $m1[$key] : '', $match)) {\n                    array_shift($match);\n                    foreach ($value as $k => $name) {\n                        if (isset($match[$k])) {\n                            $var[$name] = $match[$k];\n                        }\n                    }\n                    continue;\n                } else {\n                    return false;\n                }\n            }\n\n            if (0 === strpos($val, '[:')) {\n                // 可选参数\n                $val      = substr($val, 1, -1);\n                $optional = true;\n            } else {\n                $optional = false;\n            }\n            if (0 === strpos($val, ':')) {\n                // URL变量\n                $name = substr($val, 1);\n                if (!$optional && !isset($m1[$key])) {\n                    return false;\n                }\n                if (isset($m1[$key]) && isset($pattern[$name])) {\n                    // 检查变量规则\n                    if ($pattern[$name] instanceof \\Closure) {\n                        $result = call_user_func_array($pattern[$name], [$m1[$key]]);\n                        if (false === $result) {\n                            return false;\n                        }\n                    } elseif (!preg_match(0 === strpos($pattern[$name], '/') ? $pattern[$name] : '/^' . $pattern[$name] . '$/', $m1[$key])) {\n                        return false;\n                    }\n                }\n                $var[$name] = isset($m1[$key]) ? $m1[$key] : '';\n            } elseif (!isset($m1[$key]) || 0 !== strcasecmp($val, $m1[$key])) {\n                return false;\n            }\n        }\n        // 成功匹配后返回URL中的动态变量数组\n        return $var;\n    }\n\n    /**\n     * 解析规则路由\n     * @access private\n     * @param string    $rule 路由规则\n     * @param string    $route 路由地址\n     * @param string    $pathinfo URL地址\n     * @param array     $option 路由参数\n     * @param array     $matches 匹配的变量\n     * @return array\n     */\n    private static function parseRule($rule, $route, $pathinfo, $option = [], $matches = [])\n    {\n        $request = Request::instance();\n        // 解析路由规则\n        if ($rule) {\n            $rule = explode('/', $rule);\n            // 获取URL地址中的参数\n            $paths = explode('|', $pathinfo);\n            foreach ($rule as $item) {\n                $fun = '';\n                if (0 === strpos($item, '[:')) {\n                    $item = substr($item, 1, -1);\n                }\n                if (0 === strpos($item, ':')) {\n                    $var           = substr($item, 1);\n                    $matches[$var] = array_shift($paths);\n                } else {\n                    // 过滤URL中的静态变量\n                    array_shift($paths);\n                }\n            }\n        } else {\n            $paths = explode('|', $pathinfo);\n        }\n\n        // 获取路由地址规则\n        if (is_string($route) && isset($option['prefix'])) {\n            // 路由地址前缀\n            $route = $option['prefix'] . $route;\n        }\n        // 替换路由地址中的变量\n        if (is_string($route) && !empty($matches)) {\n            foreach ($matches as $key => $val) {\n                if (false !== strpos($route, ':' . $key)) {\n                    $route = str_replace(':' . $key, $val, $route);\n                }\n            }\n        }\n\n        // 绑定模型数据\n        if (isset($option['bind_model'])) {\n            $bind = [];\n            foreach ($option['bind_model'] as $key => $val) {\n                if ($val instanceof \\Closure) {\n                    $result = call_user_func_array($val, [$matches]);\n                } else {\n                    if (is_array($val)) {\n                        $fields    = explode('&', $val[1]);\n                        $model     = $val[0];\n                        $exception = isset($val[2]) ? $val[2] : true;\n                    } else {\n                        $fields    = ['id'];\n                        $model     = $val;\n                        $exception = true;\n                    }\n                    $where = [];\n                    $match = true;\n                    foreach ($fields as $field) {\n                        if (!isset($matches[$field])) {\n                            $match = false;\n                            break;\n                        } else {\n                            $where[$field] = $matches[$field];\n                        }\n                    }\n                    if ($match) {\n                        $query  = strpos($model, '\\\\') ? $model::where($where) : Loader::model($model)->where($where);\n                        $result = $query->failException($exception)->find();\n                    }\n                }\n                if (!empty($result)) {\n                    $bind[$key] = $result;\n                }\n            }\n            $request->bind($bind);\n        }\n\n        if (!empty($option['response'])) {\n            Hook::add('response_send', $option['response']);\n        }\n\n        // 解析额外参数\n        self::parseUrlParams(empty($paths) ? '' : implode('|', $paths), $matches);\n        // 记录匹配的路由信息\n        $request->routeInfo(['rule' => $rule, 'route' => $route, 'option' => $option, 'var' => $matches]);\n\n        // 检测路由after行为\n        if (!empty($option['after_behavior'])) {\n            if ($option['after_behavior'] instanceof \\Closure) {\n                $result = call_user_func_array($option['after_behavior'], []);\n            } else {\n                foreach ((array) $option['after_behavior'] as $behavior) {\n                    $result = Hook::exec($behavior, '');\n                    if (!is_null($result)) {\n                        break;\n                    }\n                }\n            }\n            // 路由规则重定向\n            if ($result instanceof Response) {\n                return ['type' => 'response', 'response' => $result];\n            } elseif (is_array($result)) {\n                return $result;\n            }\n        }\n\n        if ($route instanceof \\Closure) {\n            // 执行闭包\n            $result = ['type' => 'function', 'function' => $route];\n        } elseif (0 === strpos($route, '/') || strpos($route, '://')) {\n            // 路由到重定向地址\n            $result = ['type' => 'redirect', 'url' => $route, 'status' => isset($option['status']) ? $option['status'] : 301];\n        } elseif (false !== strpos($route, '\\\\')) {\n            // 路由到方法\n            list($path, $var) = self::parseUrlPath($route);\n            $route            = str_replace('/', '@', implode('/', $path));\n            $method           = strpos($route, '@') ? explode('@', $route) : $route;\n            $result           = ['type' => 'method', 'method' => $method, 'var' => $var];\n        } elseif (0 === strpos($route, '@')) {\n            // 路由到控制器\n            $route             = substr($route, 1);\n            list($route, $var) = self::parseUrlPath($route);\n            $result            = ['type' => 'controller', 'controller' => implode('/', $route), 'var' => $var];\n            $request->action(array_pop($route));\n            $request->controller($route ? array_pop($route) : Config::get('default_controller'));\n            $request->module($route ? array_pop($route) : Config::get('default_module'));\n            App::$modulePath = APP_PATH . (Config::get('app_multi_module') ? $request->module() . DS : '');\n        } else {\n            // 路由到模块/控制器/操作\n            $result = self::parseModule($route);\n        }\n        // 开启请求缓存\n        if ($request->isGet() && isset($option['cache'])) {\n            $cache = $option['cache'];\n            if (is_array($cache)) {\n                list($key, $expire) = $cache;\n            } else {\n                $key    = str_replace('|', '/', $pathinfo);\n                $expire = $cache;\n            }\n            $request->cache($key, $expire);\n        }\n        return $result;\n    }\n\n    /**\n     * 解析URL地址为 模块/控制器/操作\n     * @access private\n     * @param string    $url URL地址\n     * @return array\n     */\n    private static function parseModule($url)\n    {\n        list($path, $var) = self::parseUrlPath($url);\n        $action           = array_pop($path);\n        $controller       = !empty($path) ? array_pop($path) : null;\n        $module           = Config::get('app_multi_module') && !empty($path) ? array_pop($path) : null;\n        $method           = Request::instance()->method();\n        if (Config::get('use_action_prefix') && !empty(self::$methodPrefix[$method])) {\n            // 操作方法前缀支持\n            $action = 0 !== strpos($action, self::$methodPrefix[$method]) ? self::$methodPrefix[$method] . $action : $action;\n        }\n        // 设置当前请求的路由变量\n        Request::instance()->route($var);\n        // 路由到模块/控制器/操作\n        return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => false];\n    }\n\n    /**\n     * 解析URL地址中的参数Request对象\n     * @access private\n     * @param string    $rule 路由规则\n     * @param array     $var 变量\n     * @return void\n     */\n    private static function parseUrlParams($url, &$var = [])\n    {\n        if ($url) {\n            if (Config::get('url_param_type')) {\n                $var += explode('|', $url);\n            } else {\n                preg_replace_callback('/(\\w+)\\|([^\\|]+)/', function ($match) use (&$var) {\n                    $var[$match[1]] = strip_tags($match[2]);\n                }, $url);\n            }\n        }\n        // 设置当前请求的参数\n        Request::instance()->route($var);\n    }\n\n    // 分析路由规则中的变量\n    private static function parseVar($rule)\n    {\n        // 提取路由规则中的变量\n        $var = [];\n        foreach (explode('/', $rule) as $val) {\n            $optional = false;\n            if (false !== strpos($val, '<') && preg_match_all('/<(\\w+(\\??))>/', $val, $matches)) {\n                foreach ($matches[1] as $name) {\n                    if (strpos($name, '?')) {\n                        $name     = substr($name, 0, -1);\n                        $optional = true;\n                    } else {\n                        $optional = false;\n                    }\n                    $var[$name] = $optional ? 2 : 1;\n                }\n            }\n\n            if (0 === strpos($val, '[:')) {\n                // 可选参数\n                $optional = true;\n                $val      = substr($val, 1, -1);\n            }\n            if (0 === strpos($val, ':')) {\n                // URL变量\n                $name       = substr($val, 1);\n                $var[$name] = $optional ? 2 : 1;\n            }\n        }\n        return $var;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Session.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\exception\\ClassNotFoundException;\n\nclass Session\n{\n    protected static $prefix = '';\n    protected static $init   = null;\n\n    /**\n     * 设置或者获取session作用域（前缀）\n     * @param string $prefix\n     * @return string|void\n     */\n    public static function prefix($prefix = '')\n    {\n        if (empty($prefix) && null !== $prefix) {\n            return self::$prefix;\n        } else {\n            self::$prefix = $prefix;\n        }\n    }\n\n    /**\n     * session初始化\n     * @param array $config\n     * @return void\n     * @throws \\think\\Exception\n     */\n    public static function init(array $config = [])\n    {\n        if (empty($config)) {\n            $config = Config::get('session');\n        }\n        // 记录初始化信息\n        App::$debug && Log::record('[ SESSION ] INIT ' . var_export($config, true), 'info');\n        $isDoStart = false;\n        if (isset($config['use_trans_sid'])) {\n            ini_set('session.use_trans_sid', $config['use_trans_sid'] ? 1 : 0);\n        }\n\n        // 启动session\n        if (!empty($config['auto_start']) && PHP_SESSION_ACTIVE != session_status()) {\n            ini_set('session.auto_start', 0);\n            $isDoStart = true;\n        }\n\n        if (isset($config['prefix']) && (self::$prefix === '' || self::$prefix === null)) {\n            self::$prefix = $config['prefix'];\n        }\n        if (isset($config['var_session_id']) && isset($_REQUEST[$config['var_session_id']])) {\n            session_id($_REQUEST[$config['var_session_id']]);\n        } elseif (isset($config['id']) && !empty($config['id'])) {\n            session_id($config['id']);\n        }\n        if (isset($config['name'])) {\n            session_name($config['name']);\n        }\n        if (isset($config['path'])) {\n            session_save_path($config['path']);\n        }\n        if (isset($config['domain'])) {\n            ini_set('session.cookie_domain', $config['domain']);\n        }\n        if (isset($config['expire'])) {\n            ini_set('session.gc_maxlifetime', $config['expire']);\n            ini_set('session.cookie_lifetime', $config['expire']);\n        }\n        if (isset($config['secure'])) {\n            ini_set('session.cookie_secure', $config['secure']);\n        }\n        if (isset($config['httponly'])) {\n            ini_set('session.cookie_httponly', $config['httponly']);\n        }\n        if (isset($config['use_cookies'])) {\n            ini_set('session.use_cookies', $config['use_cookies'] ? 1 : 0);\n        }\n        if (isset($config['cache_limiter'])) {\n            session_cache_limiter($config['cache_limiter']);\n        }\n        if (isset($config['cache_expire'])) {\n            session_cache_expire($config['cache_expire']);\n        }\n        if (!empty($config['type'])) {\n            // 读取session驱动\n            $class = false !== strpos($config['type'], '\\\\') ? $config['type'] : '\\\\think\\\\session\\\\driver\\\\' . ucwords($config['type']);\n\n            // 检查驱动类\n            if (!class_exists($class) || !session_set_save_handler(new $class($config))) {\n                throw new ClassNotFoundException('error session handler:' . $class, $class);\n            }\n        }\n        if ($isDoStart) {\n            session_start();\n            self::$init = true;\n        } else {\n            self::$init = false;\n        }\n    }\n\n    /**\n     * session自动启动或者初始化\n     * @return void\n     */\n    public static function boot()\n    {\n        if (is_null(self::$init)) {\n            self::init();\n        } elseif (false === self::$init) {\n            if (PHP_SESSION_ACTIVE != session_status()) {\n                session_start();\n            }\n            self::$init = true;\n        }\n    }\n\n    /**\n     * session设置\n     * @param string        $name session名称\n     * @param mixed         $value session值\n     * @param string|null   $prefix 作用域（前缀）\n     * @return void\n     */\n    public static function set($name, $value = '', $prefix = null)\n    {\n        empty(self::$init) && self::boot();\n\n        $prefix = !is_null($prefix) ? $prefix : self::$prefix;\n        if (strpos($name, '.')) {\n            // 二维数组赋值\n            list($name1, $name2) = explode('.', $name);\n            if ($prefix) {\n                $_SESSION[$prefix][$name1][$name2] = $value;\n            } else {\n                $_SESSION[$name1][$name2] = $value;\n            }\n        } elseif ($prefix) {\n            $_SESSION[$prefix][$name] = $value;\n        } else {\n            $_SESSION[$name] = $value;\n        }\n    }\n\n    /**\n     * session获取\n     * @param string        $name session名称\n     * @param string|null   $prefix 作用域（前缀）\n     * @return mixed\n     */\n    public static function get($name = '', $prefix = null)\n    {\n        empty(self::$init) && self::boot();\n        $prefix = !is_null($prefix) ? $prefix : self::$prefix;\n        if ('' == $name) {\n            // 获取全部的session\n            $value = $prefix ? (!empty($_SESSION[$prefix]) ? $_SESSION[$prefix] : []) : $_SESSION;\n        } elseif ($prefix) {\n            // 获取session\n            if (strpos($name, '.')) {\n                list($name1, $name2) = explode('.', $name);\n                $value               = isset($_SESSION[$prefix][$name1][$name2]) ? $_SESSION[$prefix][$name1][$name2] : null;\n            } else {\n                $value = isset($_SESSION[$prefix][$name]) ? $_SESSION[$prefix][$name] : null;\n            }\n        } else {\n            if (strpos($name, '.')) {\n                list($name1, $name2) = explode('.', $name);\n                $value               = isset($_SESSION[$name1][$name2]) ? $_SESSION[$name1][$name2] : null;\n            } else {\n                $value = isset($_SESSION[$name]) ? $_SESSION[$name] : null;\n            }\n        }\n        return $value;\n    }\n\n    /**\n     * session获取并删除\n     * @param string        $name session名称\n     * @param string|null   $prefix 作用域（前缀）\n     * @return mixed\n     */\n    public static function pull($name, $prefix = null)\n    {\n        $result = self::get($name, $prefix);\n        if ($result) {\n            self::delete($name, $prefix);\n            return $result;\n        } else {\n            return;\n        }\n    }\n\n    /**\n     * session设置 下一次请求有效\n     * @param string        $name session名称\n     * @param mixed         $value session值\n     * @param string|null   $prefix 作用域（前缀）\n     * @return void\n     */\n    public static function flash($name, $value)\n    {\n        self::set($name, $value);\n        if (!self::has('__flash__.__time__')) {\n            self::set('__flash__.__time__', $_SERVER['REQUEST_TIME_FLOAT']);\n        }\n        self::push('__flash__', $name);\n    }\n\n    /**\n     * 清空当前请求的session数据\n     * @return void\n     */\n    public static function flush()\n    {\n        if (self::$init) {\n            $item = self::get('__flash__');\n\n            if (!empty($item)) {\n                $time = $item['__time__'];\n                if ($_SERVER['REQUEST_TIME_FLOAT'] > $time) {\n                    unset($item['__time__']);\n                    self::delete($item);\n                    self::set('__flash__', []);\n                }\n            }\n        }\n    }\n\n    /**\n     * 删除session数据\n     * @param string|array  $name session名称\n     * @param string|null   $prefix 作用域（前缀）\n     * @return void\n     */\n    public static function delete($name, $prefix = null)\n    {\n        empty(self::$init) && self::boot();\n        $prefix = !is_null($prefix) ? $prefix : self::$prefix;\n        if (is_array($name)) {\n            foreach ($name as $key) {\n                self::delete($key, $prefix);\n            }\n        } elseif (strpos($name, '.')) {\n            list($name1, $name2) = explode('.', $name);\n            if ($prefix) {\n                unset($_SESSION[$prefix][$name1][$name2]);\n            } else {\n                unset($_SESSION[$name1][$name2]);\n            }\n        } else {\n            if ($prefix) {\n                unset($_SESSION[$prefix][$name]);\n            } else {\n                unset($_SESSION[$name]);\n            }\n        }\n    }\n\n    /**\n     * 清空session数据\n     * @param string|null   $prefix 作用域（前缀）\n     * @return void\n     */\n    public static function clear($prefix = null)\n    {\n        empty(self::$init) && self::boot();\n        $prefix = !is_null($prefix) ? $prefix : self::$prefix;\n        if ($prefix) {\n            unset($_SESSION[$prefix]);\n        } else {\n            $_SESSION = [];\n        }\n    }\n\n    /**\n     * 判断session数据\n     * @param string        $name session名称\n     * @param string|null   $prefix\n     * @return bool\n     */\n    public static function has($name, $prefix = null)\n    {\n        empty(self::$init) && self::boot();\n        $prefix = !is_null($prefix) ? $prefix : self::$prefix;\n        if (strpos($name, '.')) {\n            // 支持数组\n            list($name1, $name2) = explode('.', $name);\n            return $prefix ? isset($_SESSION[$prefix][$name1][$name2]) : isset($_SESSION[$name1][$name2]);\n        } else {\n            return $prefix ? isset($_SESSION[$prefix][$name]) : isset($_SESSION[$name]);\n        }\n    }\n\n    /**\n     * 添加数据到一个session数组\n     * @param  string  $key\n     * @param  mixed   $value\n     * @return void\n     */\n    public static function push($key, $value)\n    {\n        $array = self::get($key);\n        if (is_null($array)) {\n            $array = [];\n        }\n        $array[] = $value;\n        self::set($key, $array);\n    }\n\n    /**\n     * 启动session\n     * @return void\n     */\n    public static function start()\n    {\n        session_start();\n        self::$init = true;\n    }\n\n    /**\n     * 销毁session\n     * @return void\n     */\n    public static function destroy()\n    {\n        if (!empty($_SESSION)) {\n            $_SESSION = [];\n        }\n        session_unset();\n        session_destroy();\n        self::$init = null;\n    }\n\n    /**\n     * 重新生成session_id\n     * @param bool $delete 是否删除关联会话文件\n     * @return void\n     */\n    private static function regenerate($delete = false)\n    {\n        session_regenerate_id($delete);\n    }\n\n    /**\n     * 暂停session\n     * @return void\n     */\n    public static function pause()\n    {\n        // 暂停session\n        session_write_close();\n        self::$init = false;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Template.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\exception\\TemplateNotFoundException;\n\n/**\n * ThinkPHP分离出来的模板引擎\n * 支持XML标签和普通标签的模板解析\n * 编译型模板引擎 支持动态缓存\n */\nclass Template\n{\n    // 模板变量\n    protected $data = [];\n    // 引擎配置\n    protected $config = [\n        'view_path'          => '', // 模板路径\n        'view_base'          => '',\n        'view_suffix'        => 'html', // 默认模板文件后缀\n        'view_depr'          => DS,\n        'cache_suffix'       => 'php', // 默认模板缓存后缀\n        'tpl_deny_func_list' => 'echo,exit', // 模板引擎禁用函数\n        'tpl_deny_php'       => false, // 默认模板引擎是否禁用PHP原生代码\n        'tpl_begin'          => '{', // 模板引擎普通标签开始标记\n        'tpl_end'            => '}', // 模板引擎普通标签结束标记\n        'strip_space'        => false, // 是否去除模板文件里面的html空格与换行\n        'tpl_cache'          => true, // 是否开启模板编译缓存,设为false则每次都会重新编译\n        'compile_type'       => 'file', // 模板编译类型\n        'cache_prefix'       => '', // 模板缓存前缀标识，可以动态改变\n        'cache_time'         => 0, // 模板缓存有效期 0 为永久，(以数字为值，单位:秒)\n        'layout_on'          => false, // 布局模板开关\n        'layout_name'        => 'layout', // 布局模板入口文件\n        'layout_item'        => '{__CONTENT__}', // 布局模板的内容替换标识\n        'taglib_begin'       => '{', // 标签库标签开始标记\n        'taglib_end'         => '}', // 标签库标签结束标记\n        'taglib_load'        => true, // 是否使用内置标签库之外的其它标签库，默认自动检测\n        'taglib_build_in'    => 'cx', // 内置标签库名称(标签使用不必指定标签库名称),以逗号分隔 注意解析顺序\n        'taglib_pre_load'    => '', // 需要额外加载的标签库(须指定标签库名称)，多个以逗号分隔\n        'display_cache'      => false, // 模板渲染缓存\n        'cache_id'           => '', // 模板缓存ID\n        'tpl_replace_string' => [],\n        'tpl_var_identify'   => 'array', // .语法变量识别，array|object|'', 为空时自动识别\n    ];\n\n    private $literal     = [];\n    private $includeFile = []; // 记录所有模板包含的文件路径及更新时间\n    protected $storage;\n\n    /**\n     * 构造函数\n     * @access public\n     */\n    public function __construct(array $config = [])\n    {\n        $this->config['cache_path']   = TEMP_PATH;\n        $this->config                 = array_merge($this->config, $config);\n        $this->config['taglib_begin'] = $this->stripPreg($this->config['taglib_begin']);\n        $this->config['taglib_end']   = $this->stripPreg($this->config['taglib_end']);\n        $this->config['tpl_begin']    = $this->stripPreg($this->config['tpl_begin']);\n        $this->config['tpl_end']      = $this->stripPreg($this->config['tpl_end']);\n\n        // 初始化模板编译存储器\n        $type          = $this->config['compile_type'] ? $this->config['compile_type'] : 'File';\n        $class         = false !== strpos($type, '\\\\') ? $type : '\\\\think\\\\template\\\\driver\\\\' . ucwords($type);\n        $this->storage = new $class();\n    }\n\n    /**\n     * 字符串替换 避免正则混淆\n     * @access private\n     * @param string $str\n     * @return string\n     */\n    private function stripPreg($str)\n    {\n        return str_replace(\n            ['{', '}', '(', ')', '|', '[', ']', '-', '+', '*', '.', '^', '?'],\n            ['\\{', '\\}', '\\(', '\\)', '\\|', '\\[', '\\]', '\\-', '\\+', '\\*', '\\.', '\\^', '\\?'],\n            $str);\n    }\n\n    /**\n     * 模板变量赋值\n     * @access public\n     * @param mixed $name\n     * @param mixed $value\n     * @return void\n     */\n    public function assign($name, $value = '')\n    {\n        if (is_array($name)) {\n            $this->data = array_merge($this->data, $name);\n        } else {\n            $this->data[$name] = $value;\n        }\n    }\n\n    /**\n     * 模板引擎参数赋值\n     * @access public\n     * @param mixed $name\n     * @param mixed $value\n     */\n    public function __set($name, $value)\n    {\n        $this->config[$name] = $value;\n    }\n\n    /**\n     * 模板引擎配置项\n     * @access public\n     * @param array|string $config\n     * @return void|array\n     */\n    public function config($config)\n    {\n        if (is_array($config)) {\n            $this->config = array_merge($this->config, $config);\n        } elseif (isset($this->config[$config])) {\n            return $this->config[$config];\n        } else {\n            return;\n        }\n    }\n\n    /**\n     * 模板变量获取\n     * @access public\n     * @param  string $name 变量名\n     * @return mixed\n     */\n    public function get($name = '')\n    {\n        if ('' == $name) {\n            return $this->data;\n        } else {\n            $data = $this->data;\n            foreach (explode('.', $name) as $key => $val) {\n                if (isset($data[$val])) {\n                    $data = $data[$val];\n                } else {\n                    $data = null;\n                    break;\n                }\n            }\n            return $data;\n        }\n    }\n\n    /**\n     * 渲染模板文件\n     * @access public\n     * @param string    $template 模板文件\n     * @param array     $vars 模板变量\n     * @param array     $config 模板参数\n     * @return void\n     */\n    public function fetch($template, $vars = [], $config = [])\n    {\n        if ($vars) {\n            $this->data = $vars;\n        }\n        if ($config) {\n            $this->config($config);\n        }\n        if (!empty($this->config['cache_id']) && $this->config['display_cache']) {\n            // 读取渲染缓存\n            $cacheContent = Cache::get($this->config['cache_id']);\n            if (false !== $cacheContent) {\n                echo $cacheContent;\n                return;\n            }\n        }\n        $template = $this->parseTemplateFile($template);\n        if ($template) {\n            $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($template) . '.' . ltrim($this->config['cache_suffix'], '.');\n            if (!$this->checkCache($cacheFile)) {\n                // 缓存无效 重新模板编译\n                $content = file_get_contents($template);\n                $this->compiler($content, $cacheFile);\n            }\n            // 页面缓存\n            ob_start();\n            ob_implicit_flush(0);\n            // 读取编译存储\n            $this->storage->read($cacheFile, $this->data);\n            // 获取并清空缓存\n            $content = ob_get_clean();\n            if (!empty($this->config['cache_id']) && $this->config['display_cache']) {\n                // 缓存页面输出\n                Cache::set($this->config['cache_id'], $content, $this->config['cache_time']);\n            }\n            echo $content;\n        }\n    }\n\n    /**\n     * 渲染模板内容\n     * @access public\n     * @param string    $content 模板内容\n     * @param array     $vars 模板变量\n     * @param array     $config 模板参数\n     * @return void\n     */\n    public function display($content, $vars = [], $config = [])\n    {\n        if ($vars) {\n            $this->data = $vars;\n        }\n        if ($config) {\n            $this->config($config);\n        }\n        $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($content) . '.' . ltrim($this->config['cache_suffix'], '.');\n        if (!$this->checkCache($cacheFile)) {\n            // 缓存无效 模板编译\n            $this->compiler($content, $cacheFile);\n        }\n        // 读取编译存储\n        $this->storage->read($cacheFile, $this->data);\n    }\n\n    /**\n     * 设置布局\n     * @access public\n     * @param mixed     $name 布局模板名称 false 则关闭布局\n     * @param string    $replace 布局模板内容替换标识\n     * @return object\n     */\n    public function layout($name, $replace = '')\n    {\n        if (false === $name) {\n            // 关闭布局\n            $this->config['layout_on'] = false;\n        } else {\n            // 开启布局\n            $this->config['layout_on'] = true;\n            // 名称必须为字符串\n            if (is_string($name)) {\n                $this->config['layout_name'] = $name;\n            }\n            if (!empty($replace)) {\n                $this->config['layout_item'] = $replace;\n            }\n        }\n        return $this;\n    }\n\n    /**\n     * 检查编译缓存是否有效\n     * 如果无效则需要重新编译\n     * @access private\n     * @param string $cacheFile 缓存文件名\n     * @return boolean\n     */\n    private function checkCache($cacheFile)\n    {\n        // 未开启缓存功能\n        if (!$this->config['tpl_cache']) {\n            return false;\n        }\n        // 缓存文件不存在\n        if (!is_file($cacheFile)) {\n            return false;\n        }\n        // 读取缓存文件失败\n        if (!$handle = @fopen($cacheFile, \"r\")) {\n            return false;\n        }\n        // 读取第一行\n        preg_match('/\\/\\*(.+?)\\*\\//', fgets($handle), $matches);\n        if (!isset($matches[1])) {\n            return false;\n        }\n        $includeFile = unserialize($matches[1]);\n        if (!is_array($includeFile)) {\n            return false;\n        }\n        // 检查模板文件是否有更新\n        foreach ($includeFile as $path => $time) {\n            if (is_file($path) && filemtime($path) > $time) {\n                // 模板文件如果有更新则缓存需要更新\n                return false;\n            }\n        }\n        // 检查编译存储是否有效\n        return $this->storage->check($cacheFile, $this->config['cache_time']);\n    }\n\n    /**\n     * 检查编译缓存是否存在\n     * @access public\n     * @param string $cacheId 缓存的id\n     * @return boolean\n     */\n    public function isCache($cacheId)\n    {\n        if ($cacheId && $this->config['display_cache']) {\n            // 缓存页面输出\n            return Cache::has($cacheId);\n        }\n        return false;\n    }\n\n    /**\n     * 编译模板文件内容\n     * @access private\n     * @param string    $content 模板内容\n     * @param string    $cacheFile 缓存文件名\n     * @return void\n     */\n    private function compiler(&$content, $cacheFile)\n    {\n        // 判断是否启用布局\n        if ($this->config['layout_on']) {\n            if (false !== strpos($content, '{__NOLAYOUT__}')) {\n                // 可以单独定义不使用布局\n                $content = str_replace('{__NOLAYOUT__}', '', $content);\n            } else {\n                // 读取布局模板\n                $layoutFile = $this->parseTemplateFile($this->config['layout_name']);\n                if ($layoutFile) {\n                    // 替换布局的主体内容\n                    $content = str_replace($this->config['layout_item'], $content, file_get_contents($layoutFile));\n                }\n            }\n        } else {\n            $content = str_replace('{__NOLAYOUT__}', '', $content);\n        }\n\n        // 模板解析\n        $this->parse($content);\n        if ($this->config['strip_space']) {\n            /* 去除html空格与换行 */\n            $find    = ['~>\\s+<~', '~>(\\s+\\n|\\r)~'];\n            $replace = ['><', '>'];\n            $content = preg_replace($find, $replace, $content);\n        }\n        // 优化生成的php代码\n        $content = preg_replace('/\\?>\\s*<\\?php\\s(?!echo\\b)/s', '', $content);\n        // 模板过滤输出\n        $replace = $this->config['tpl_replace_string'];\n        $content = str_replace(array_keys($replace), array_values($replace), $content);\n        // 添加安全代码及模板引用记录\n        $content = '<?php if (!defined(\\'THINK_PATH\\')) exit(); /*' . serialize($this->includeFile) . '*/ ?>' . \"\\n\" . $content;\n        // 编译存储\n        $this->storage->write($cacheFile, $content);\n        $this->includeFile = [];\n        return;\n    }\n\n    /**\n     * 模板解析入口\n     * 支持普通标签和TagLib解析 支持自定义标签库\n     * @access public\n     * @param string $content 要解析的模板内容\n     * @return void\n     */\n    public function parse(&$content)\n    {\n        // 内容为空不解析\n        if (empty($content)) {\n            return;\n        }\n        // 替换literal标签内容\n        $this->parseLiteral($content);\n        // 解析继承\n        $this->parseExtend($content);\n        // 解析布局\n        $this->parseLayout($content);\n        // 检查include语法\n        $this->parseInclude($content);\n        // 替换包含文件中literal标签内容\n        $this->parseLiteral($content);\n        // 检查PHP语法\n        $this->parsePhp($content);\n\n        // 获取需要引入的标签库列表\n        // 标签库只需要定义一次，允许引入多个一次\n        // 一般放在文件的最前面\n        // 格式：<taglib name=\"html,mytag...\" />\n        // 当TAGLIB_LOAD配置为true时才会进行检测\n        if ($this->config['taglib_load']) {\n            $tagLibs = $this->getIncludeTagLib($content);\n            if (!empty($tagLibs)) {\n                // 对导入的TagLib进行解析\n                foreach ($tagLibs as $tagLibName) {\n                    $this->parseTagLib($tagLibName, $content);\n                }\n            }\n        }\n        // 预先加载的标签库 无需在每个模板中使用taglib标签加载 但必须使用标签库XML前缀\n        if ($this->config['taglib_pre_load']) {\n            $tagLibs = explode(',', $this->config['taglib_pre_load']);\n            foreach ($tagLibs as $tag) {\n                $this->parseTagLib($tag, $content);\n            }\n        }\n        // 内置标签库 无需使用taglib标签导入就可以使用 并且不需使用标签库XML前缀\n        $tagLibs = explode(',', $this->config['taglib_build_in']);\n        foreach ($tagLibs as $tag) {\n            $this->parseTagLib($tag, $content, true);\n        }\n        // 解析普通模板标签 {$tagName}\n        $this->parseTag($content);\n\n        // 还原被替换的Literal标签\n        $this->parseLiteral($content, true);\n        return;\n    }\n\n    /**\n     * 检查PHP语法\n     * @access private\n     * @param string $content 要解析的模板内容\n     * @return void\n     * @throws \\think\\Exception\n     */\n    private function parsePhp(&$content)\n    {\n        // 短标签的情况要将<?标签用echo方式输出 否则无法正常输出xml标识\n        $content = preg_replace('/(<\\?(?!php|=|$))/i', '<?php echo \\'\\\\1\\'; ?>' . \"\\n\", $content);\n        // PHP语法检查\n        if ($this->config['tpl_deny_php'] && false !== strpos($content, '<?php')) {\n            throw new Exception('not allow php tag', 11600);\n        }\n        return;\n    }\n\n    /**\n     * 解析模板中的布局标签\n     * @access private\n     * @param string $content 要解析的模板内容\n     * @return void\n     */\n    private function parseLayout(&$content)\n    {\n        // 读取模板中的布局标签\n        if (preg_match($this->getRegex('layout'), $content, $matches)) {\n            // 替换Layout标签\n            $content = str_replace($matches[0], '', $content);\n            // 解析Layout标签\n            $array = $this->parseAttr($matches[0]);\n            if (!$this->config['layout_on'] || $this->config['layout_name'] != $array['name']) {\n                // 读取布局模板\n                $layoutFile = $this->parseTemplateFile($array['name']);\n                if ($layoutFile) {\n                    $replace = isset($array['replace']) ? $array['replace'] : $this->config['layout_item'];\n                    // 替换布局的主体内容\n                    $content = str_replace($replace, $content, file_get_contents($layoutFile));\n                }\n            }\n        } else {\n            $content = str_replace('{__NOLAYOUT__}', '', $content);\n        }\n        return;\n    }\n\n    /**\n     * 解析模板中的include标签\n     * @access private\n     * @param  string $content 要解析的模板内容\n     * @return void\n     */\n    private function parseInclude(&$content)\n    {\n        $regex = $this->getRegex('include');\n        $func  = function ($template) use (&$func, &$regex, &$content) {\n            if (preg_match_all($regex, $template, $matches, PREG_SET_ORDER)) {\n                foreach ($matches as $match) {\n                    $array = $this->parseAttr($match[0]);\n                    $file  = $array['file'];\n                    unset($array['file']);\n                    // 分析模板文件名并读取内容\n                    $parseStr = $this->parseTemplateName($file);\n                    foreach ($array as $k => $v) {\n                        // 以$开头字符串转换成模板变量\n                        if (0 === strpos($v, '$')) {\n                            $v = $this->get(substr($v, 1));\n                        }\n                        $parseStr = str_replace('[' . $k . ']', $v, $parseStr);\n                    }\n                    $content = str_replace($match[0], $parseStr, $content);\n                    // 再次对包含文件进行模板分析\n                    $func($parseStr);\n                }\n                unset($matches);\n            }\n        };\n        // 替换模板中的include标签\n        $func($content);\n        return;\n    }\n\n    /**\n     * 解析模板中的extend标签\n     * @access private\n     * @param  string $content 要解析的模板内容\n     * @return void\n     */\n    private function parseExtend(&$content)\n    {\n        $regex  = $this->getRegex('extend');\n        $array  = $blocks  = $baseBlocks  = [];\n        $extend = '';\n        $func   = function ($template) use (&$func, &$regex, &$array, &$extend, &$blocks, &$baseBlocks) {\n            if (preg_match($regex, $template, $matches)) {\n                if (!isset($array[$matches['name']])) {\n                    $array[$matches['name']] = 1;\n                    // 读取继承模板\n                    $extend = $this->parseTemplateName($matches['name']);\n                    // 递归检查继承\n                    $func($extend);\n                    // 取得block标签内容\n                    $blocks = array_merge($blocks, $this->parseBlock($template));\n                    return;\n                }\n            } else {\n                // 取得顶层模板block标签内容\n                $baseBlocks = $this->parseBlock($template, true);\n                if (empty($extend)) {\n                    // 无extend标签但有block标签的情况\n                    $extend = $template;\n                }\n            }\n        };\n\n        $func($content);\n        if (!empty($extend)) {\n            if ($baseBlocks) {\n                $children = [];\n                foreach ($baseBlocks as $name => $val) {\n                    $replace = $val['content'];\n                    if (!empty($children[$name])) {\n                        // 如果包含有子block标签\n                        foreach ($children[$name] as $key) {\n                            $replace = str_replace($baseBlocks[$key]['begin'] . $baseBlocks[$key]['content'] . $baseBlocks[$key]['end'], $blocks[$key]['content'], $replace);\n                        }\n                    }\n                    if (isset($blocks[$name])) {\n                        // 带有{__block__}表示与所继承模板的相应标签合并，而不是覆盖\n                        $replace = str_replace(['{__BLOCK__}', '{__block__}'], $replace, $blocks[$name]['content']);\n                        if (!empty($val['parent'])) {\n                            // 如果不是最顶层的block标签\n                            $parent = $val['parent'];\n                            if (isset($blocks[$parent])) {\n                                $blocks[$parent]['content'] = str_replace($blocks[$name]['begin'] . $blocks[$name]['content'] . $blocks[$name]['end'], $replace, $blocks[$parent]['content']);\n                            }\n                            $blocks[$name]['content'] = $replace;\n                            $children[$parent][]      = $name;\n                            continue;\n                        }\n                    } elseif (!empty($val['parent'])) {\n                        // 如果子标签没有被继承则用原值\n                        $children[$val['parent']][] = $name;\n                        $blocks[$name]              = $val;\n                    }\n                    if (!$val['parent']) {\n                        // 替换模板中的顶级block标签\n                        $extend = str_replace($val['begin'] . $val['content'] . $val['end'], $replace, $extend);\n                    }\n                }\n            }\n            $content = $extend;\n            unset($blocks, $baseBlocks);\n        }\n        return;\n    }\n\n    /**\n     * 替换页面中的literal标签\n     * @access private\n     * @param  string   $content 模板内容\n     * @param  boolean  $restore 是否为还原\n     * @return void\n     */\n    private function parseLiteral(&$content, $restore = false)\n    {\n        $regex = $this->getRegex($restore ? 'restoreliteral' : 'literal');\n        if (preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {\n            if (!$restore) {\n                $count = count($this->literal);\n                // 替换literal标签\n                foreach ($matches as $match) {\n                    $this->literal[] = substr($match[0], strlen($match[1]), -strlen($match[2]));\n                    $content         = str_replace($match[0], \"<!--###literal{$count}###-->\", $content);\n                    $count++;\n                }\n            } else {\n                // 还原literal标签\n                foreach ($matches as $match) {\n                    $content = str_replace($match[0], $this->literal[$match[1]], $content);\n                }\n                // 清空literal记录\n                $this->literal = [];\n            }\n            unset($matches);\n        }\n        return;\n    }\n\n    /**\n     * 获取模板中的block标签\n     * @access private\n     * @param  string   $content 模板内容\n     * @param  boolean  $sort 是否排序\n     * @return array\n     */\n    private function parseBlock(&$content, $sort = false)\n    {\n        $regex  = $this->getRegex('block');\n        $result = [];\n        if (preg_match_all($regex, $content, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {\n            $right = $keys = [];\n            foreach ($matches as $match) {\n                if (empty($match['name'][0])) {\n                    if (count($right) > 0) {\n                        $tag                  = array_pop($right);\n                        $start                = $tag['offset'] + strlen($tag['tag']);\n                        $length               = $match[0][1] - $start;\n                        $result[$tag['name']] = [\n                            'begin'   => $tag['tag'],\n                            'content' => substr($content, $start, $length),\n                            'end'     => $match[0][0],\n                            'parent'  => count($right) ? end($right)['name'] : '',\n                        ];\n                        $keys[$tag['name']] = $match[0][1];\n                    }\n                } else {\n                    // 标签头压入栈\n                    $right[] = [\n                        'name'   => $match[2][0],\n                        'offset' => $match[0][1],\n                        'tag'    => $match[0][0],\n                    ];\n                }\n            }\n            unset($right, $matches);\n            if ($sort) {\n                // 按block标签结束符在模板中的位置排序\n                array_multisort($keys, $result);\n            }\n        }\n        return $result;\n    }\n\n    /**\n     * 搜索模板页面中包含的TagLib库\n     * 并返回列表\n     * @access private\n     * @param  string $content 模板内容\n     * @return array|null\n     */\n    private function getIncludeTagLib(&$content)\n    {\n        // 搜索是否有TagLib标签\n        if (preg_match($this->getRegex('taglib'), $content, $matches)) {\n            // 替换TagLib标签\n            $content = str_replace($matches[0], '', $content);\n            return explode(',', $matches['name']);\n        }\n        return;\n    }\n\n    /**\n     * TagLib库解析\n     * @access public\n     * @param  string   $tagLib 要解析的标签库\n     * @param  string   $content 要解析的模板内容\n     * @param  boolean  $hide 是否隐藏标签库前缀\n     * @return void\n     */\n    public function parseTagLib($tagLib, &$content, $hide = false)\n    {\n        if (false !== strpos($tagLib, '\\\\')) {\n            // 支持指定标签库的命名空间\n            $className = $tagLib;\n            $tagLib    = substr($tagLib, strrpos($tagLib, '\\\\') + 1);\n        } else {\n            $className = '\\\\think\\\\template\\\\taglib\\\\' . ucwords($tagLib);\n        }\n        $tLib = new $className($this);\n        $tLib->parseTag($content, $hide ? '' : $tagLib);\n        return;\n    }\n\n    /**\n     * 分析标签属性\n     * @access public\n     * @param  string   $str 属性字符串\n     * @param  string   $name 不为空时返回指定的属性名\n     * @return array\n     */\n    public function parseAttr($str, $name = null)\n    {\n        $regex = '/\\s+(?>(?P<name>[\\w-]+)\\s*)=(?>\\s*)([\\\"\\'])(?P<value>(?:(?!\\\\2).)*)\\\\2/is';\n        $array = [];\n        if (preg_match_all($regex, $str, $matches, PREG_SET_ORDER)) {\n            foreach ($matches as $match) {\n                $array[$match['name']] = $match['value'];\n            }\n            unset($matches);\n        }\n        if (!empty($name) && isset($array[$name])) {\n            return $array[$name];\n        } else {\n            return $array;\n        }\n    }\n\n    /**\n     * 模板标签解析\n     * 格式： {TagName:args [|content] }\n     * @access private\n     * @param  string $content 要解析的模板内容\n     * @return void\n     */\n    private function parseTag(&$content)\n    {\n        $regex = $this->getRegex('tag');\n        if (preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {\n            foreach ($matches as $match) {\n                $str  = stripslashes($match[1]);\n                $flag = substr($str, 0, 1);\n                switch ($flag) {\n                    case '$':\n                        // 解析模板变量 格式 {$varName}\n                        // 是否带有?号\n                        if (false !== $pos = strpos($str, '?')) {\n                            $array = preg_split('/([!=]={1,2}|(?<!-)[><]={0,1})/', substr($str, 0, $pos), 2, PREG_SPLIT_DELIM_CAPTURE);\n                            $name  = $array[0];\n                            $this->parseVar($name);\n                            $this->parseVarFunction($name);\n\n                            $str = trim(substr($str, $pos + 1));\n                            $this->parseVar($str);\n                            $first = substr($str, 0, 1);\n                            if (strpos($name, ')')) {\n                                // $name为对象或是自动识别，或者含有函数\n                                if (isset($array[1])) {\n                                    $this->parseVar($array[2]);\n                                    $name .= $array[1] . $array[2];\n                                }\n                                switch ($first) {\n                                    case '?':\n                                        $str = '<?php echo (' . $name . ') ? ' . $name . ' : ' . substr($str, 1) . '; ?>';\n                                        break;\n                                    case '=':\n                                        $str = '<?php if(' . $name . ') echo ' . substr($str, 1) . '; ?>';\n                                        break;\n                                    default:\n                                        $str = '<?php echo ' . $name . '?' . $str . '; ?>';\n                                }\n                            } else {\n                                if (isset($array[1])) {\n                                    $this->parseVar($array[2]);\n                                    $_name = ' && ' . $name . $array[1] . $array[2];\n                                } else {\n                                    $_name = '';\n                                }\n                                // $name为数组\n                                switch ($first) {\n                                    case '?':\n                                        // {$varname??'xxx'} $varname有定义则输出$varname,否则输出xxx\n                                        $str = '<?php echo isset(' . $name . ')' . $_name . ' ? ' . $name . ' : ' . substr($str, 1) . '; ?>';\n                                        break;\n                                    case '=':\n                                        // {$varname?='xxx'} $varname为真时才输出xxx\n                                        $str = '<?php if(!empty(' . $name . ')' . $_name . ') echo ' . substr($str, 1) . '; ?>';\n                                        break;\n                                    case ':':\n                                        // {$varname?:'xxx'} $varname为真时输出$varname,否则输出xxx\n                                        $str = '<?php echo !empty(' . $name . ')' . $_name . '?' . $name . $str . '; ?>';\n                                        break;\n                                    default:\n                                        if (strpos($str, ':')) {\n                                            // {$varname ? 'a' : 'b'} $varname为真时输出a,否则输出b\n                                            $str = '<?php echo !empty(' . $name . ')' . $_name . '?' . $str . '; ?>';\n                                        } else {\n                                            $str = '<?php echo ' . $_name . '?' . $str . '; ?>';\n                                        }\n                                }\n                            }\n                        } else {\n                            $this->parseVar($str);\n                            $this->parseVarFunction($str);\n                            $str = '<?php echo ' . $str . '; ?>';\n                        }\n                        break;\n                    case ':':\n                        // 输出某个函数的结果\n                        $str = substr($str, 1);\n                        $this->parseVar($str);\n                        $str = '<?php echo ' . $str . '; ?>';\n                        break;\n                    case '~':\n                        // 执行某个函数\n                        $str = substr($str, 1);\n                        $this->parseVar($str);\n                        $str = '<?php ' . $str . '; ?>';\n                        break;\n                    case '-':\n                    case '+':\n                        // 输出计算\n                        $this->parseVar($str);\n                        $str = '<?php echo ' . $str . '; ?>';\n                        break;\n                    case '/':\n                        // 注释标签\n                        $flag2 = substr($str, 1, 1);\n                        if ('/' == $flag2 || ('*' == $flag2 && substr(rtrim($str), -2) == '*/')) {\n                            $str = '';\n                        }\n                        break;\n                    default:\n                        // 未识别的标签直接返回\n                        $str = $this->config['tpl_begin'] . $str . $this->config['tpl_end'];\n                        break;\n                }\n                $content = str_replace($match[0], $str, $content);\n            }\n            unset($matches);\n        }\n        return;\n    }\n\n    /**\n     * 模板变量解析,支持使用函数\n     * 格式： {$varname|function1|function2=arg1,arg2}\n     * @access public\n     * @param  string $varStr 变量数据\n     * @return void\n     */\n    public function parseVar(&$varStr)\n    {\n        $varStr = trim($varStr);\n        if (preg_match_all('/\\$[a-zA-Z_](?>\\w*)(?:[:\\.][0-9a-zA-Z_](?>\\w*))+/', $varStr, $matches, PREG_OFFSET_CAPTURE)) {\n            static $_varParseList = [];\n            while ($matches[0]) {\n                $match = array_pop($matches[0]);\n                //如果已经解析过该变量字串，则直接返回变量值\n                if (isset($_varParseList[$match[0]])) {\n                    $parseStr = $_varParseList[$match[0]];\n                } else {\n                    if (strpos($match[0], '.')) {\n                        $vars  = explode('.', $match[0]);\n                        $first = array_shift($vars);\n                        if ('$Think' == $first) {\n                            // 所有以Think.打头的以特殊变量对待 无需模板赋值就可以输出\n                            $parseStr = $this->parseThinkVar($vars);\n                        } elseif ('$Request' == $first) {\n                            // 获取Request请求对象参数\n                            $method = array_shift($vars);\n                            if (!empty($vars)) {\n                                $params = implode('.', $vars);\n                                if ('true' != $params) {\n                                    $params = '\\'' . $params . '\\'';\n                                }\n                            } else {\n                                $params = '';\n                            }\n                            $parseStr = '\\think\\Request::instance()->' . $method . '(' . $params . ')';\n                        } else {\n                            switch ($this->config['tpl_var_identify']) {\n                                case 'array': // 识别为数组\n                                    $parseStr = $first . '[\\'' . implode('\\'][\\'', $vars) . '\\']';\n                                    break;\n                                case 'obj': // 识别为对象\n                                    $parseStr = $first . '->' . implode('->', $vars);\n                                    break;\n                                default: // 自动判断数组或对象\n                                    $parseStr = '(is_array(' . $first . ')?' . $first . '[\\'' . implode('\\'][\\'', $vars) . '\\']:' . $first . '->' . implode('->', $vars) . ')';\n                            }\n                        }\n                    } else {\n                        $parseStr = str_replace(':', '->', $match[0]);\n                    }\n                    $_varParseList[$match[0]] = $parseStr;\n                }\n                $varStr = substr_replace($varStr, $parseStr, $match[1], strlen($match[0]));\n            }\n            unset($matches);\n        }\n        return;\n    }\n\n    /**\n     * 对模板中使用了函数的变量进行解析\n     * 格式 {$varname|function1|function2=arg1,arg2}\n     * @access public\n     * @param  string $varStr 变量字符串\n     * @return void\n     */\n    public function parseVarFunction(&$varStr)\n    {\n        if (false == strpos($varStr, '|')) {\n            return;\n        }\n        static $_varFunctionList = [];\n        $_key                    = md5($varStr);\n        //如果已经解析过该变量字串，则直接返回变量值\n        if (isset($_varFunctionList[$_key])) {\n            $varStr = $_varFunctionList[$_key];\n        } else {\n            $varArray = explode('|', $varStr);\n            // 取得变量名称\n            $name = array_shift($varArray);\n            // 对变量使用函数\n            $length = count($varArray);\n            // 取得模板禁止使用函数列表\n            $template_deny_funs = explode(',', $this->config['tpl_deny_func_list']);\n            for ($i = 0; $i < $length; $i++) {\n                $args = explode('=', $varArray[$i], 2);\n                // 模板函数过滤\n                $fun = trim($args[0]);\n                switch ($fun) {\n                    case 'default': // 特殊模板函数\n                        if (false === strpos($name, '(')) {\n                            $name = '(isset(' . $name . ') && (' . $name . ' !== \\'\\')?' . $name . ':' . $args[1] . ')';\n                        } else {\n                            $name = '(' . $name . ' ?: ' . $args[1] . ')';\n                        }\n                        break;\n                    default: // 通用模板函数\n                        if (!in_array($fun, $template_deny_funs)) {\n                            if (isset($args[1])) {\n                                if (strstr($args[1], '###')) {\n                                    $args[1] = str_replace('###', $name, $args[1]);\n                                    $name    = \"$fun($args[1])\";\n                                } else {\n                                    $name = \"$fun($name,$args[1])\";\n                                }\n                            } else {\n                                if (!empty($args[0])) {\n                                    $name = \"$fun($name)\";\n                                }\n                            }\n                        }\n                }\n            }\n            $_varFunctionList[$_key] = $name;\n            $varStr                  = $name;\n        }\n        return;\n    }\n\n    /**\n     * 特殊模板变量解析\n     * 格式 以 $Think. 打头的变量属于特殊模板变量\n     * @access public\n     * @param  array $vars 变量数组\n     * @return string\n     */\n    public function parseThinkVar($vars)\n    {\n        $type  = strtoupper(trim(array_shift($vars)));\n        $param = implode('.', $vars);\n        if ($vars) {\n            switch ($type) {\n                case 'SERVER':\n                    $parseStr = '\\\\think\\\\Request::instance()->server(\\'' . $param . '\\')';\n                    break;\n                case 'GET':\n                    $parseStr = '\\\\think\\\\Request::instance()->get(\\'' . $param . '\\')';\n                    break;\n                case 'POST':\n                    $parseStr = '\\\\think\\\\Request::instance()->post(\\'' . $param . '\\')';\n                    break;\n                case 'COOKIE':\n                    $parseStr = '\\\\think\\\\Cookie::get(\\'' . $param . '\\')';\n                    break;\n                case 'SESSION':\n                    $parseStr = '\\\\think\\\\Session::get(\\'' . $param . '\\')';\n                    break;\n                case 'ENV':\n                    $parseStr = '\\\\think\\\\Request::instance()->env(\\'' . $param . '\\')';\n                    break;\n                case 'REQUEST':\n                    $parseStr = '\\\\think\\\\Request::instance()->request(\\'' . $param . '\\')';\n                    break;\n                case 'CONST':\n                    $parseStr = strtoupper($param);\n                    break;\n                case 'LANG':\n                    $parseStr = '\\\\think\\\\Lang::get(\\'' . $param . '\\')';\n                    break;\n                case 'CONFIG':\n                    $parseStr = '\\\\think\\\\Config::get(\\'' . $param . '\\')';\n                    break;\n                default:\n                    $parseStr = '\\'\\'';\n                    break;\n            }\n        } else {\n            switch ($type) {\n                case 'NOW':\n                    $parseStr = \"date('Y-m-d g:i a',time())\";\n                    break;\n                case 'VERSION':\n                    $parseStr = 'THINK_VERSION';\n                    break;\n                case 'LDELIM':\n                    $parseStr = '\\'' . ltrim($this->config['tpl_begin'], '\\\\') . '\\'';\n                    break;\n                case 'RDELIM':\n                    $parseStr = '\\'' . ltrim($this->config['tpl_end'], '\\\\') . '\\'';\n                    break;\n                default:\n                    if (defined($type)) {\n                        $parseStr = $type;\n                    } else {\n                        $parseStr = '';\n                    }\n            }\n        }\n        return $parseStr;\n    }\n\n    /**\n     * 分析加载的模板文件并读取内容 支持多个模板文件读取\n     * @access private\n     * @param  string $templateName 模板文件名\n     * @return string\n     */\n    private function parseTemplateName($templateName)\n    {\n        $array    = explode(',', $templateName);\n        $parseStr = '';\n        foreach ($array as $templateName) {\n            if (empty($templateName)) {\n                continue;\n            }\n            if (0 === strpos($templateName, '$')) {\n                //支持加载变量文件名\n                $templateName = $this->get(substr($templateName, 1));\n            }\n            $template = $this->parseTemplateFile($templateName);\n            if ($template) {\n                // 获取模板文件内容\n                $parseStr .= file_get_contents($template);\n            }\n        }\n        return $parseStr;\n    }\n\n    /**\n     * 解析模板文件名\n     * @access private\n     * @param  string $template 文件名\n     * @return string|false\n     */\n    private function parseTemplateFile($template)\n    {\n        if ('' == pathinfo($template, PATHINFO_EXTENSION)) {\n            if (strpos($template, '@')) {\n                list($module, $template) = explode('@', $template);\n            }\n            if (0 !== strpos($template, '/')) {\n                $template = str_replace(['/', ':'], $this->config['view_depr'], $template);\n            } else {\n                $template = str_replace(['/', ':'], $this->config['view_depr'], substr($template, 1));\n            }\n            if ($this->config['view_base']) {\n                $module = isset($module) ? $module : Request::instance()->module();\n                $path   = $this->config['view_base'] . ($module ? $module . DS : '');\n            } else {\n                $path = isset($module) ? APP_PATH . $module . DS . basename($this->config['view_path']) . DS : $this->config['view_path'];\n            }\n            $template = $path . $template . '.' . ltrim($this->config['view_suffix'], '.');\n        }\n\n        if (is_file($template)) {\n            // 记录模板文件的更新时间\n            $this->includeFile[$template] = filemtime($template);\n            return $template;\n        } else {\n            throw new TemplateNotFoundException('template not exists:' . $template, $template);\n        }\n    }\n\n    /**\n     * 按标签生成正则\n     * @access private\n     * @param  string $tagName 标签名\n     * @return string\n     */\n    private function getRegex($tagName)\n    {\n        $regex = '';\n        if ('tag' == $tagName) {\n            $begin = $this->config['tpl_begin'];\n            $end   = $this->config['tpl_end'];\n            if (strlen(ltrim($begin, '\\\\')) == 1 && strlen(ltrim($end, '\\\\')) == 1) {\n                $regex = $begin . '((?:[\\$]{1,2}[a-wA-w_]|[\\:\\~][\\$a-wA-w_]|[+]{2}[\\$][a-wA-w_]|[-]{2}[\\$][a-wA-w_]|\\/[\\*\\/])(?>[^' . $end . ']*))' . $end;\n            } else {\n                $regex = $begin . '((?:[\\$]{1,2}[a-wA-w_]|[\\:\\~][\\$a-wA-w_]|[+]{2}[\\$][a-wA-w_]|[-]{2}[\\$][a-wA-w_]|\\/[\\*\\/])(?>(?:(?!' . $end . ').)*))' . $end;\n            }\n        } else {\n            $begin  = $this->config['taglib_begin'];\n            $end    = $this->config['taglib_end'];\n            $single = strlen(ltrim($begin, '\\\\')) == 1 && strlen(ltrim($end, '\\\\')) == 1 ? true : false;\n            switch ($tagName) {\n                case 'block':\n                    if ($single) {\n                        $regex = $begin . '(?:' . $tagName . '\\b(?>(?:(?!name=).)*)\\bname=([\\'\\\"])(?P<name>[\\$\\w\\-\\/\\.]+)\\\\1(?>[^' . $end . ']*)|\\/' . $tagName . ')' . $end;\n                    } else {\n                        $regex = $begin . '(?:' . $tagName . '\\b(?>(?:(?!name=).)*)\\bname=([\\'\\\"])(?P<name>[\\$\\w\\-\\/\\.]+)\\\\1(?>(?:(?!' . $end . ').)*)|\\/' . $tagName . ')' . $end;\n                    }\n                    break;\n                case 'literal':\n                    if ($single) {\n                        $regex = '(' . $begin . $tagName . '\\b(?>[^' . $end . ']*)' . $end . ')';\n                        $regex .= '(?:(?>[^' . $begin . ']*)(?>(?!' . $begin . '(?>' . $tagName . '\\b[^' . $end . ']*|\\/' . $tagName . ')' . $end . ')' . $begin . '[^' . $begin . ']*)*)';\n                        $regex .= '(' . $begin . '\\/' . $tagName . $end . ')';\n                    } else {\n                        $regex = '(' . $begin . $tagName . '\\b(?>(?:(?!' . $end . ').)*)' . $end . ')';\n                        $regex .= '(?:(?>(?:(?!' . $begin . ').)*)(?>(?!' . $begin . '(?>' . $tagName . '\\b(?>(?:(?!' . $end . ').)*)|\\/' . $tagName . ')' . $end . ')' . $begin . '(?>(?:(?!' . $begin . ').)*))*)';\n                        $regex .= '(' . $begin . '\\/' . $tagName . $end . ')';\n                    }\n                    break;\n                case 'restoreliteral':\n                    $regex = '<!--###literal(\\d+)###-->';\n                    break;\n                case 'include':\n                    $name = 'file';\n                case 'taglib':\n                case 'layout':\n                case 'extend':\n                    if (empty($name)) {\n                        $name = 'name';\n                    }\n                    if ($single) {\n                        $regex = $begin . $tagName . '\\b(?>(?:(?!' . $name . '=).)*)\\b' . $name . '=([\\'\\\"])(?P<name>[\\$\\w\\-\\/\\.\\:@,\\\\\\\\]+)\\\\1(?>[^' . $end . ']*)' . $end;\n                    } else {\n                        $regex = $begin . $tagName . '\\b(?>(?:(?!' . $name . '=).)*)\\b' . $name . '=([\\'\\\"])(?P<name>[\\$\\w\\-\\/\\.\\:@,\\\\\\\\]+)\\\\1(?>(?:(?!' . $end . ').)*)' . $end;\n                    }\n                    break;\n            }\n        }\n        return '/' . $regex . '/is';\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Url.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nclass Url\n{\n    // 生成URL地址的root\n    protected static $root;\n    protected static $bindCheck;\n\n    /**\n     * URL生成 支持路由反射\n     * @param string            $url 路由地址\n     * @param string|array      $vars 参数（支持数组和字符串）a=val&b=val2... ['a'=>'val1', 'b'=>'val2']\n     * @param string|bool       $suffix 伪静态后缀，默认为true表示获取配置值\n     * @param boolean|string    $domain 是否显示域名 或者直接传入域名\n     * @return string\n     */\n    public static function build($url = '', $vars = '', $suffix = true, $domain = false)\n    {\n        if (false === $domain && Route::rules('domain')) {\n            $domain = true;\n        }\n        // 解析URL\n        if (0 === strpos($url, '[') && $pos = strpos($url, ']')) {\n            // [name] 表示使用路由命名标识生成URL\n            $name = substr($url, 1, $pos - 1);\n            $url  = 'name' . substr($url, $pos + 1);\n        }\n        if (false === strpos($url, '://') && 0 !== strpos($url, '/')) {\n            $info = parse_url($url);\n            $url  = !empty($info['path']) ? $info['path'] : '';\n            if (isset($info['fragment'])) {\n                // 解析锚点\n                $anchor = $info['fragment'];\n                if (false !== strpos($anchor, '?')) {\n                    // 解析参数\n                    list($anchor, $info['query']) = explode('?', $anchor, 2);\n                }\n                if (false !== strpos($anchor, '@')) {\n                    // 解析域名\n                    list($anchor, $domain) = explode('@', $anchor, 2);\n                }\n            } elseif (strpos($url, '@') && false === strpos($url, '\\\\')) {\n                // 解析域名\n                list($url, $domain) = explode('@', $url, 2);\n            }\n        }\n\n        // 解析参数\n        if (is_string($vars)) {\n            // aaa=1&bbb=2 转换成数组\n            parse_str($vars, $vars);\n        }\n\n        if ($url) {\n            $rule = Route::name(isset($name) ? $name : $url . (isset($info['query']) ? '?' . $info['query'] : ''));\n            if (is_null($rule) && isset($info['query'])) {\n                $rule = Route::name($url);\n                // 解析地址里面参数 合并到vars\n                parse_str($info['query'], $params);\n                $vars = array_merge($params, $vars);\n                unset($info['query']);\n            }\n        }\n        if (!empty($rule) && $match = self::getRuleUrl($rule, $vars)) {\n            // 匹配路由命名标识\n            $url = $match[0];\n            // 替换可选分隔符\n            $url = preg_replace(['/(\\W)\\?$/', '/(\\W)\\?/'], ['', '\\1'], $url);\n            if (!empty($match[1])) {\n                $domain = $match[1];\n            }\n            if (!is_null($match[2])) {\n                $suffix = $match[2];\n            }\n        } elseif (!empty($rule) && isset($name)) {\n            throw new \\InvalidArgumentException('route name not exists:' . $name);\n        } else {\n            // 检查别名路由\n            $alias      = Route::rules('alias');\n            $matchAlias = false;\n            if ($alias) {\n                // 别名路由解析\n                foreach ($alias as $key => $val) {\n                    if (is_array($val)) {\n                        $val = $val[0];\n                    }\n                    if (0 === strpos($url, $val)) {\n                        $url        = $key . substr($url, strlen($val));\n                        $matchAlias = true;\n                        break;\n                    }\n                }\n            }\n            if (!$matchAlias) {\n                // 路由标识不存在 直接解析\n                $url = self::parseUrl($url, $domain);\n            }\n            if (isset($info['query'])) {\n                // 解析地址里面参数 合并到vars\n                parse_str($info['query'], $params);\n                $vars = array_merge($params, $vars);\n            }\n        }\n\n        // 检测URL绑定\n        if (!self::$bindCheck) {\n            $type = Route::getBind('type');\n            if ($type) {\n                $bind = Route::getBind($type);\n                if (0 === strpos($url, $bind)) {\n                    $url = substr($url, strlen($bind) + 1);\n                }\n            }\n        }\n        // 还原URL分隔符\n        $depr = Config::get('pathinfo_depr');\n        $url  = str_replace('/', $depr, $url);\n\n        // URL后缀\n        $suffix = in_array($url, ['/', '']) ? '' : self::parseSuffix($suffix);\n        // 锚点\n        $anchor = !empty($anchor) ? '#' . $anchor : '';\n        // 参数组装\n        if (!empty($vars)) {\n            // 添加参数\n            if (Config::get('url_common_param')) {\n                $vars = urldecode(http_build_query($vars));\n                $url .= $suffix . '?' . $vars . $anchor;\n            } else {\n                $paramType = Config::get('url_param_type');\n                foreach ($vars as $var => $val) {\n                    if ('' !== trim($val)) {\n                        if ($paramType) {\n                            $url .= $depr . urlencode($val);\n                        } else {\n                            $url .= $depr . $var . $depr . urlencode($val);\n                        }\n                    }\n                }\n                $url .= $suffix . $anchor;\n            }\n        } else {\n            $url .= $suffix . $anchor;\n        }\n        // 检测域名\n        $domain = self::parseDomain($url, $domain);\n        // URL组装\n        $url = $domain . rtrim(self::$root ?: Request::instance()->root(), '/') . '/' . ltrim($url, '/');\n\n        self::$bindCheck = false;\n        return $url;\n    }\n\n    // 直接解析URL地址\n    protected static function parseUrl($url, &$domain)\n    {\n        $request = Request::instance();\n        if (0 === strpos($url, '/')) {\n            // 直接作为路由地址解析\n            $url = substr($url, 1);\n        } elseif (false !== strpos($url, '\\\\')) {\n            // 解析到类\n            $url = ltrim(str_replace('\\\\', '/', $url), '/');\n        } elseif (0 === strpos($url, '@')) {\n            // 解析到控制器\n            $url = substr($url, 1);\n        } else {\n            // 解析到 模块/控制器/操作\n            $module  = $request->module();\n            $domains = Route::rules('domain');\n            if (true === $domain && 2 == substr_count($url, '/')) {\n                $current = $request->host();\n                $match   = [];\n                $pos     = [];\n                foreach ($domains as $key => $item) {\n                    if (isset($item['[bind]']) && 0 === strpos($url, $item['[bind]'][0])) {\n                        $pos[$key] = strlen($item['[bind]'][0]) + 1;\n                        $match[]   = $key;\n                        $module    = '';\n                    }\n                }\n                if ($match) {\n                    $domain = current($match);\n                    foreach ($match as $item) {\n                        if (0 === strpos($current, $item)) {\n                            $domain = $item;\n                        }\n                    }\n                    self::$bindCheck = true;\n                    $url             = substr($url, $pos[$domain]);\n                }\n            } elseif ($domain) {\n                if (isset($domains[$domain]['[bind]'][0])) {\n                    $bindModule = $domains[$domain]['[bind]'][0];\n                    if ($bindModule && !in_array($bindModule[0], ['\\\\', '@'])) {\n                        $module = '';\n                    }\n                }\n            }\n            $module = $module ? $module . '/' : '';\n\n            $controller = Loader::parseName($request->controller());\n            if ('' == $url) {\n                // 空字符串输出当前的 模块/控制器/操作\n                $url = $module . $controller . '/' . $request->action();\n            } else {\n                $path       = explode('/', $url);\n                $action     = Config::get('url_convert') ? strtolower(array_pop($path)) : array_pop($path);\n                $controller = empty($path) ? $controller : (Config::get('url_convert') ? Loader::parseName(array_pop($path)) : array_pop($path));\n                $module     = empty($path) ? $module : array_pop($path) . '/';\n                $url        = $module . $controller . '/' . $action;\n            }\n        }\n        return $url;\n    }\n\n    // 检测域名\n    protected static function parseDomain(&$url, $domain)\n    {\n        if (!$domain) {\n            return '';\n        }\n        $request    = Request::instance();\n        $rootDomain = Config::get('url_domain_root');\n        if (true === $domain) {\n            // 自动判断域名\n            $domain = Config::get('app_host') ?: $request->host();\n\n            $domains = Route::rules('domain');\n            if ($domains) {\n                $route_domain = array_keys($domains);\n                foreach ($route_domain as $domain_prefix) {\n                    if (0 === strpos($domain_prefix, '*.') && strpos($domain, ltrim($domain_prefix, '*.')) !== false) {\n                        foreach ($domains as $key => $rule) {\n                            $rule = is_array($rule) ? $rule[0] : $rule;\n                            if (is_string($rule) && false === strpos($key, '*') && 0 === strpos($url, $rule)) {\n                                $url    = ltrim($url, $rule);\n                                $domain = $key;\n                                // 生成对应子域名\n                                if (!empty($rootDomain)) {\n                                    $domain .= $rootDomain;\n                                }\n                                break;\n                            } elseif (false !== strpos($key, '*')) {\n                                if (!empty($rootDomain)) {\n                                    $domain .= $rootDomain;\n                                }\n                                break;\n                            }\n                        }\n                    }\n                }\n            }\n\n        } else {\n            if (empty($rootDomain)) {\n                $host       = Config::get('app_host') ?: $request->host();\n                $rootDomain = substr_count($host, '.') > 1 ? substr(strstr($host, '.'), 1) : $host;\n            }\n            if (substr_count($domain, '.') < 2 && !strpos($domain, $rootDomain)) {\n                $domain .= '.' . $rootDomain;\n            }\n        }\n        if (false !== strpos($domain, ':')) {\n            $scheme = '';\n        } else {\n            $scheme = $request->isSsl() || Config::get('is_https') ? 'https://' : 'http://';\n        }\n        return $scheme . $domain;\n    }\n\n    // 解析URL后缀\n    protected static function parseSuffix($suffix)\n    {\n        if ($suffix) {\n            $suffix = true === $suffix ? Config::get('url_html_suffix') : $suffix;\n            if ($pos = strpos($suffix, '|')) {\n                $suffix = substr($suffix, 0, $pos);\n            }\n        }\n        return (empty($suffix) || 0 === strpos($suffix, '.')) ? $suffix : '.' . $suffix;\n    }\n\n    // 匹配路由地址\n    public static function getRuleUrl($rule, &$vars = [])\n    {\n        foreach ($rule as $item) {\n            list($url, $pattern, $domain, $suffix) = $item;\n            if (empty($pattern)) {\n                return [$url, $domain, $suffix];\n            }\n            foreach ($pattern as $key => $val) {\n                if (isset($vars[$key])) {\n                    $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key . '', '<' . $key . '>'], urlencode($vars[$key]), $url);\n                    unset($vars[$key]);\n                    $result = [$url, $domain, $suffix];\n                } elseif (2 == $val) {\n                    $url    = str_replace(['/[:' . $key . ']', '[:' . $key . ']', '<' . $key . '?>'], '', $url);\n                    $result = [$url, $domain, $suffix];\n                } else {\n                    break;\n                }\n            }\n            if (isset($result)) {\n                return $result;\n            }\n        }\n        return false;\n    }\n\n    // 指定当前生成URL地址的root\n    public static function root($root)\n    {\n        self::$root = $root;\n        Request::instance()->root($root);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/Validate.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nuse think\\exception\\ClassNotFoundException;\n\nclass Validate\n{\n    // 实例\n    protected static $instance;\n\n    // 自定义的验证类型\n    protected static $type = [];\n\n    // 验证类型别名\n    protected $alias = [\n        '>' => 'gt', '>=' => 'egt', '<' => 'lt', '<=' => 'elt', '=' => 'eq', 'same' => 'eq',\n    ];\n\n    // 当前验证的规则\n    protected $rule = [];\n\n    // 验证提示信息\n    protected $message = [];\n    // 验证字段描述\n    protected $field = [];\n\n    // 验证规则默认提示信息\n    protected static $typeMsg = [\n        'require'     => ':attribute不能为空',\n        'number'      => ':attribute必须是数字',\n        'float'       => ':attribute必须是浮点数',\n        'boolean'     => ':attribute必须是布尔值',\n        'email'       => ':attribute格式不符',\n        'array'       => ':attribute必须是数组',\n        'accepted'    => ':attribute必须是yes、on或者1',\n        'date'        => ':attribute格式不符合',\n        'file'        => ':attribute不是有效的上传文件',\n        'image'       => ':attribute不是有效的图像文件',\n        'alpha'       => ':attribute只能是字母',\n        'alphaNum'    => ':attribute只能是字母和数字',\n        'alphaDash'   => ':attribute只能是字母、数字和下划线_及破折号-',\n        'activeUrl'   => ':attribute不是有效的域名或者IP',\n        'chs'         => ':attribute只能是汉字',\n        'chsAlpha'    => ':attribute只能是汉字、字母',\n        'chsAlphaNum' => ':attribute只能是汉字、字母和数字',\n        'chsDash'     => ':attribute只能是汉字、字母、数字和下划线_及破折号-',\n        'url'         => ':attribute不是有效的URL地址',\n        'ip'          => ':attribute不是有效的IP地址',\n        'dateFormat'  => ':attribute必须使用日期格式 :rule',\n        'in'          => ':attribute必须在 :rule 范围内',\n        'notIn'       => ':attribute不能在 :rule 范围内',\n        'between'     => ':attribute只能在 :1 - :2 之间',\n        'notBetween'  => ':attribute不能在 :1 - :2 之间',\n        'length'      => ':attribute长度不符合要求 :rule',\n        'max'         => ':attribute长度不能超过 :rule',\n        'min'         => ':attribute长度不能小于 :rule',\n        'after'       => ':attribute日期不能小于 :rule',\n        'before'      => ':attribute日期不能超过 :rule',\n        'expire'      => '不在有效期内 :rule',\n        'allowIp'     => '不允许的IP访问',\n        'denyIp'      => '禁止的IP访问',\n        'confirm'     => ':attribute和确认字段:2不一致',\n        'different'   => ':attribute和比较字段:2不能相同',\n        'egt'         => ':attribute必须大于等于 :rule',\n        'gt'          => ':attribute必须大于 :rule',\n        'elt'         => ':attribute必须小于等于 :rule',\n        'lt'          => ':attribute必须小于 :rule',\n        'eq'          => ':attribute必须等于 :rule',\n        'unique'      => ':attribute已存在',\n        'regex'       => ':attribute不符合指定规则',\n        'method'      => '无效的请求类型',\n        'token'       => '令牌数据无效',\n        'fileSize'    => '上传文件大小不符',\n        'fileExt'     => '上传文件后缀不符',\n        'fileMime'    => '上传文件类型不符',\n\n    ];\n\n    // 当前验证场景\n    protected $currentScene = null;\n\n    // 正则表达式 regex = ['zip'=>'\\d{6}',...]\n    protected $regex = [];\n\n    // 验证场景 scene = ['edit'=>'name1,name2,...']\n    protected $scene = [];\n\n    // 验证失败错误信息\n    protected $error = [];\n\n    // 批量验证\n    protected $batch = false;\n\n    /**\n     * 构造函数\n     * @access public\n     * @param array $rules 验证规则\n     * @param array $message 验证提示信息\n     * @param array $field 验证字段描述信息\n     */\n    public function __construct(array $rules = [], $message = [], $field = [])\n    {\n        $this->rule    = array_merge($this->rule, $rules);\n        $this->message = array_merge($this->message, $message);\n        $this->field   = array_merge($this->field, $field);\n    }\n\n    /**\n     * 实例化验证\n     * @access public\n     * @param array     $rules 验证规则\n     * @param array     $message 验证提示信息\n     * @param array     $field 验证字段描述信息\n     * @return Validate\n     */\n    public static function make($rules = [], $message = [], $field = [])\n    {\n        if (is_null(self::$instance)) {\n            self::$instance = new self($rules, $message, $field);\n        }\n        return self::$instance;\n    }\n\n    /**\n     * 添加字段验证规则\n     * @access protected\n     * @param string|array  $name  字段名称或者规则数组\n     * @param mixed         $rule  验证规则\n     * @return Validate\n     */\n    public function rule($name, $rule = '')\n    {\n        if (is_array($name)) {\n            $this->rule = array_merge($this->rule, $name);\n        } else {\n            $this->rule[$name] = $rule;\n        }\n        return $this;\n    }\n\n    /**\n     * 注册验证（类型）规则\n     * @access public\n     * @param string    $type  验证规则类型\n     * @param mixed     $callback callback方法(或闭包)\n     * @return void\n     */\n    public static function extend($type, $callback = null)\n    {\n        if (is_array($type)) {\n            self::$type = array_merge(self::$type, $type);\n        } else {\n            self::$type[$type] = $callback;\n        }\n    }\n\n    /**\n     * 设置验证规则的默认提示信息\n     * @access protected\n     * @param string|array  $type  验证规则类型名称或者数组\n     * @param string        $msg  验证提示信息\n     * @return void\n     */\n    public static function setTypeMsg($type, $msg = null)\n    {\n        if (is_array($type)) {\n            self::$typeMsg = array_merge(self::$typeMsg, $type);\n        } else {\n            self::$typeMsg[$type] = $msg;\n        }\n    }\n\n    /**\n     * 设置提示信息\n     * @access public\n     * @param string|array  $name  字段名称\n     * @param string        $message 提示信息\n     * @return Validate\n     */\n    public function message($name, $message = '')\n    {\n        if (is_array($name)) {\n            $this->message = array_merge($this->message, $name);\n        } else {\n            $this->message[$name] = $message;\n        }\n        return $this;\n    }\n\n    /**\n     * 设置验证场景\n     * @access public\n     * @param string|array  $name  场景名或者场景设置数组\n     * @param mixed         $fields 要验证的字段\n     * @return Validate\n     */\n    public function scene($name, $fields = null)\n    {\n        if (is_array($name)) {\n            $this->scene = array_merge($this->scene, $name);\n        }if (is_null($fields)) {\n            // 设置当前场景\n            $this->currentScene = $name;\n        } else {\n            // 设置验证场景\n            $this->scene[$name] = $fields;\n        }\n        return $this;\n    }\n\n    /**\n     * 判断是否存在某个验证场景\n     * @access public\n     * @param string $name 场景名\n     * @return bool\n     */\n    public function hasScene($name)\n    {\n        return isset($this->scene[$name]);\n    }\n\n    /**\n     * 设置批量验证\n     * @access public\n     * @param bool $batch  是否批量验证\n     * @return Validate\n     */\n    public function batch($batch = true)\n    {\n        $this->batch = $batch;\n        return $this;\n    }\n\n    /**\n     * 数据自动验证\n     * @access public\n     * @param array     $data  数据\n     * @param mixed     $rules  验证规则\n     * @param string    $scene 验证场景\n     * @return bool\n     */\n    public function check($data, $rules = [], $scene = '')\n    {\n        $this->error = [];\n\n        if (empty($rules)) {\n            // 读取验证规则\n            $rules = $this->rule;\n        }\n\n        // 分析验证规则\n        $scene = $this->getScene($scene);\n        if (is_array($scene)) {\n            // 处理场景验证字段\n            $change = [];\n            $array  = [];\n            foreach ($scene as $k => $val) {\n                if (is_numeric($k)) {\n                    $array[] = $val;\n                } else {\n                    $array[]    = $k;\n                    $change[$k] = $val;\n                }\n            }\n        }\n\n        foreach ($rules as $key => $item) {\n            // field => rule1|rule2... field=>['rule1','rule2',...]\n            if (is_numeric($key)) {\n                // [field,rule1|rule2,msg1|msg2]\n                $key  = $item[0];\n                $rule = $item[1];\n                if (isset($item[2])) {\n                    $msg = is_string($item[2]) ? explode('|', $item[2]) : $item[2];\n                } else {\n                    $msg = [];\n                }\n            } else {\n                $rule = $item;\n                $msg  = [];\n            }\n            if (strpos($key, '|')) {\n                // 字段|描述 用于指定属性名称\n                list($key, $title) = explode('|', $key);\n            } else {\n                $title = isset($this->field[$key]) ? $this->field[$key] : $key;\n            }\n\n            // 场景检测\n            if (!empty($scene)) {\n                if ($scene instanceof \\Closure && !call_user_func_array($scene, [$key, $data])) {\n                    continue;\n                } elseif (is_array($scene)) {\n                    if (!in_array($key, $array)) {\n                        continue;\n                    } elseif (isset($change[$key])) {\n                        // 重载某个验证规则\n                        $rule = $change[$key];\n                    }\n                }\n            }\n\n            // 获取数据 支持二维数组\n            $value = $this->getDataValue($data, $key);\n\n            // 字段验证\n            if ($rule instanceof \\Closure) {\n                // 匿名函数验证 支持传入当前字段和所有字段两个数据\n                $result = call_user_func_array($rule, [$value, $data]);\n            } else {\n                $result = $this->checkItem($key, $value, $rule, $data, $title, $msg);\n            }\n\n            if (true !== $result) {\n                // 没有返回true 则表示验证失败\n                if (!empty($this->batch)) {\n                    // 批量验证\n                    if (is_array($result)) {\n                        $this->error = array_merge($this->error, $result);\n                    } else {\n                        $this->error[$key] = $result;\n                    }\n                } else {\n                    $this->error = $result;\n                    return false;\n                }\n            }\n        }\n        return !empty($this->error) ? false : true;\n    }\n\n    /**\n     * 验证单个字段规则\n     * @access protected\n     * @param string    $field  字段名\n     * @param mixed     $value  字段值\n     * @param mixed     $rules  验证规则\n     * @param array     $data  数据\n     * @param string    $title  字段描述\n     * @param array     $msg  提示信息\n     * @return mixed\n     */\n    protected function checkItem($field, $value, $rules, $data, $title = '', $msg = [])\n    {\n        // 支持多规则验证 require|in:a,b,c|... 或者 ['require','in'=>'a,b,c',...]\n        if (is_string($rules)) {\n            $rules = explode('|', $rules);\n        }\n        $i = 0;\n        foreach ($rules as $key => $rule) {\n            if ($rule instanceof \\Closure) {\n                $result = call_user_func_array($rule, [$value, $data]);\n                $info   = is_numeric($key) ? '' : $key;\n            } else {\n                // 判断验证类型\n                if (is_numeric($key)) {\n                    if (strpos($rule, ':')) {\n                        list($type, $rule) = explode(':', $rule, 2);\n                        if (isset($this->alias[$type])) {\n                            // 判断别名\n                            $type = $this->alias[$type];\n                        }\n                        $info = $type;\n                    } elseif (method_exists($this, $rule)) {\n                        $type = $rule;\n                        $info = $rule;\n                        $rule = '';\n                    } else {\n                        $type = 'is';\n                        $info = $rule;\n                    }\n                } else {\n                    $info = $type = $key;\n                }\n\n                // 如果不是require 有数据才会行验证\n                if (0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) {\n                    // 验证类型\n                    $callback = isset(self::$type[$type]) ? self::$type[$type] : [$this, $type];\n                    // 验证数据\n                    $result = call_user_func_array($callback, [$value, $rule, $data, $field, $title]);\n                } else {\n                    $result = true;\n                }\n            }\n\n            if (false === $result) {\n                // 验证失败 返回错误信息\n                if (isset($msg[$i])) {\n                    $message = $msg[$i];\n                    if (is_string($message) && strpos($message, '{%') === 0) {\n                        $message = Lang::get(substr($message, 2, -1));\n                    }\n                } else {\n                    $message = $this->getRuleMsg($field, $title, $info, $rule);\n                }\n                return $message;\n            } elseif (true !== $result) {\n                // 返回自定义错误信息\n                if (is_string($result) && false !== strpos($result, ':')) {\n                    $result = str_replace([':attribute', ':rule'], [$title, (string) $rule], $result);\n                }\n                return $result;\n            }\n            $i++;\n        }\n        return $result;\n    }\n\n    /**\n     * 验证是否和某个字段的值一致\n     * @access protected\n     * @param mixed     $value 字段值\n     * @param mixed     $rule  验证规则\n     * @param array     $data  数据\n     * @param string    $field 字段名\n     * @return bool\n     */\n    protected function confirm($value, $rule, $data, $field = '')\n    {\n        if ('' == $rule) {\n            if (strpos($field, '_confirm')) {\n                $rule = strstr($field, '_confirm', true);\n            } else {\n                $rule = $field . '_confirm';\n            }\n        }\n        return $this->getDataValue($data, $rule) === $value;\n    }\n\n    /**\n     * 验证是否和某个字段的值是否不同\n     * @access protected\n     * @param mixed $value 字段值\n     * @param mixed $rule  验证规则\n     * @param array $data  数据\n     * @return bool\n     */\n    protected function different($value, $rule, $data)\n    {\n        return $this->getDataValue($data, $rule) != $value;\n    }\n\n    /**\n     * 验证是否大于等于某个值\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @param array     $data  数据\n     * @return bool\n     */\n    protected function egt($value, $rule, $data)\n    {\n        $val = $this->getDataValue($data, $rule);\n        return !is_null($val) && $value >= $val;\n    }\n\n    /**\n     * 验证是否大于某个值\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @param array     $data  数据\n     * @return bool\n     */\n    protected function gt($value, $rule, $data)\n    {\n        $val = $this->getDataValue($data, $rule);\n        return !is_null($val) && $value > $val;\n    }\n\n    /**\n     * 验证是否小于等于某个值\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @param array     $data  数据\n     * @return bool\n     */\n    protected function elt($value, $rule, $data)\n    {\n        $val = $this->getDataValue($data, $rule);\n        return !is_null($val) && $value <= $val;\n    }\n\n    /**\n     * 验证是否小于某个值\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @param array     $data  数据\n     * @return bool\n     */\n    protected function lt($value, $rule, $data)\n    {\n        $val = $this->getDataValue($data, $rule);\n        return !is_null($val) && $value < $val;\n    }\n\n    /**\n     * 验证是否等于某个值\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function eq($value, $rule)\n    {\n        return $value == $rule;\n    }\n\n    /**\n     * 验证字段值是否为有效格式\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param string    $rule  验证规则\n     * @param array     $data  验证数据\n     * @return bool\n     */\n    protected function is($value, $rule, $data = [])\n    {\n        switch ($rule) {\n            case 'require':\n                // 必须\n                $result = !empty($value) || '0' == $value;\n                break;\n            case 'accepted':\n                // 接受\n                $result = in_array($value, ['1', 'on', 'yes']);\n                break;\n            case 'date':\n                // 是否是一个有效日期\n                $result = false !== strtotime($value);\n                break;\n            case 'alpha':\n                // 只允许字母\n                $result = $this->regex($value, '/^[A-Za-z]+$/');\n                break;\n            case 'alphaNum':\n                // 只允许字母和数字\n                $result = $this->regex($value, '/^[A-Za-z0-9]+$/');\n                break;\n            case 'alphaDash':\n                // 只允许字母、数字和下划线 破折号\n                $result = $this->regex($value, '/^[A-Za-z0-9\\-\\_]+$/');\n                break;\n            case 'chs':\n                // 只允许汉字\n                $result = $this->regex($value, '/^[\\x{4e00}-\\x{9fa5}]+$/u');\n                break;\n            case 'chsAlpha':\n                // 只允许汉字、字母\n                $result = $this->regex($value, '/^[\\x{4e00}-\\x{9fa5}a-zA-Z]+$/u');\n                break;\n            case 'chsAlphaNum':\n                // 只允许汉字、字母和数字\n                $result = $this->regex($value, '/^[\\x{4e00}-\\x{9fa5}a-zA-Z0-9]+$/u');\n                break;\n            case 'chsDash':\n                // 只允许汉字、字母、数字和下划线_及破折号-\n                $result = $this->regex($value, '/^[\\x{4e00}-\\x{9fa5}a-zA-Z0-9\\_\\-]+$/u');\n                break;\n            case 'activeUrl':\n                // 是否为有效的网址\n                $result = checkdnsrr($value);\n                break;\n            case 'ip':\n                // 是否为IP地址\n                $result = $this->filter($value, [FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6]);\n                break;\n            case 'url':\n                // 是否为一个URL地址\n                $result = $this->filter($value, FILTER_VALIDATE_URL);\n                break;\n            case 'float':\n                // 是否为float\n                $result = $this->filter($value, FILTER_VALIDATE_FLOAT);\n                break;\n            case 'number':\n                $result = is_numeric($value);\n                break;\n            case 'integer':\n                // 是否为整型\n                $result = $this->filter($value, FILTER_VALIDATE_INT);\n                break;\n            case 'email':\n                // 是否为邮箱地址\n                $result = $this->filter($value, FILTER_VALIDATE_EMAIL);\n                break;\n            case 'boolean':\n                // 是否为布尔值\n                $result = in_array($value, [true, false, 0, 1, '0', '1'], true);\n                break;\n            case 'array':\n                // 是否为数组\n                $result = is_array($value);\n                break;\n            case 'file':\n                $result = $value instanceof File;\n                break;\n            case 'image':\n                $result = $value instanceof File && in_array($this->getImageType($value->getRealPath()), [1, 2, 3, 6]);\n                break;\n            case 'token':\n                $result = $this->token($value, '__token__', $data);\n                break;\n            default:\n                if (isset(self::$type[$rule])) {\n                    // 注册的验证规则\n                    $result = call_user_func_array(self::$type[$rule], [$value]);\n                } else {\n                    // 正则验证\n                    $result = $this->regex($value, $rule);\n                }\n        }\n        return $result;\n    }\n\n    // 判断图像类型\n    protected function getImageType($image)\n    {\n        if (function_exists('exif_imagetype')) {\n            return exif_imagetype($image);\n        } else {\n            $info = getimagesize($image);\n            return $info[2];\n        }\n    }\n\n    /**\n     * 验证是否为合格的域名或者IP 支持A，MX，NS，SOA，PTR，CNAME，AAAA，A6， SRV，NAPTR，TXT 或者 ANY类型\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function activeUrl($value, $rule)\n    {\n        if (!in_array($rule, ['A', 'MX', 'NS', 'SOA', 'PTR', 'CNAME', 'AAAA', 'A6', 'SRV', 'NAPTR', 'TXT', 'ANY'])) {\n            $rule = 'MX';\n        }\n        return checkdnsrr($value, $rule);\n    }\n\n    /**\n     * 验证是否有效IP\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则 ipv4 ipv6\n     * @return bool\n     */\n    protected function ip($value, $rule)\n    {\n        if (!in_array($rule, ['ipv4', 'ipv6'])) {\n            $rule = 'ipv4';\n        }\n        return $this->filter($value, [FILTER_VALIDATE_IP, 'ipv6' == $rule ? FILTER_FLAG_IPV6 : FILTER_FLAG_IPV4]);\n    }\n\n    /**\n     * 验证上传文件后缀\n     * @access protected\n     * @param mixed     $file  上传文件\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function fileExt($file, $rule)\n    {\n        if (!($file instanceof File)) {\n            return false;\n        }\n        if (is_string($rule)) {\n            $rule = explode(',', $rule);\n        }\n        if (is_array($file)) {\n            foreach ($file as $item) {\n                if (!$item->checkExt($rule)) {\n                    return false;\n                }\n            }\n            return true;\n        } else {\n            return $file->checkExt($rule);\n        }\n    }\n\n    /**\n     * 验证上传文件类型\n     * @access protected\n     * @param mixed     $file  上传文件\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function fileMime($file, $rule)\n    {\n        if (!($file instanceof File)) {\n            return false;\n        }\n        if (is_string($rule)) {\n            $rule = explode(',', $rule);\n        }\n        if (is_array($file)) {\n            foreach ($file as $item) {\n                if (!$item->checkMime($rule)) {\n                    return false;\n                }\n            }\n            return true;\n        } else {\n            return $file->checkMime($rule);\n        }\n    }\n\n    /**\n     * 验证上传文件大小\n     * @access protected\n     * @param mixed     $file  上传文件\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function fileSize($file, $rule)\n    {\n        if (!($file instanceof File)) {\n            return false;\n        }\n        if (is_array($file)) {\n            foreach ($file as $item) {\n                if (!$item->checkSize($rule)) {\n                    return false;\n                }\n            }\n            return true;\n        } else {\n            return $file->checkSize($rule);\n        }\n    }\n\n    /**\n     * 验证图片的宽高及类型\n     * @access protected\n     * @param mixed     $file  上传文件\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function image($file, $rule)\n    {\n        if (!($file instanceof File)) {\n            return false;\n        }\n        if ($rule) {\n            $rule                        = explode(',', $rule);\n            list($width, $height, $type) = getimagesize($file->getRealPath());\n            if (isset($rule[2])) {\n                $imageType = strtolower($rule[2]);\n                if ('jpeg' == $imageType) {\n                    $imageType = 'jpg';\n                }\n                if (image_type_to_extension($type, false) != $imageType) {\n                    return false;\n                }\n            }\n\n            list($w, $h) = $rule;\n            return $w == $width && $h == $height;\n        } else {\n            return in_array($this->getImageType($file->getRealPath()), [1, 2, 3, 6]);\n        }\n    }\n\n    /**\n     * 验证请求类型\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function method($value, $rule)\n    {\n        $method = Request::instance()->method();\n        return strtoupper($rule) == $method;\n    }\n\n    /**\n     * 验证时间和日期是否符合指定格式\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function dateFormat($value, $rule)\n    {\n        $info = date_parse_from_format($rule, $value);\n        return 0 == $info['warning_count'] && 0 == $info['error_count'];\n    }\n\n    /**\n     * 验证是否唯一\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则 格式：数据表,字段名,排除ID,主键名\n     * @param array     $data  数据\n     * @param string    $field  验证字段名\n     * @return bool\n     */\n    protected function unique($value, $rule, $data, $field)\n    {\n        if (is_string($rule)) {\n            $rule = explode(',', $rule);\n        }\n        if (false !== strpos($rule[0], '\\\\')) {\n            // 指定模型类\n            $db = new $rule[0];\n        } else {\n            try {\n                $db = Loader::model($rule[0]);\n            } catch (ClassNotFoundException $e) {\n                $db = Db::name($rule[0]);\n            }\n        }\n        $key = isset($rule[1]) ? $rule[1] : $field;\n\n        if (strpos($key, '^')) {\n            // 支持多个字段验证\n            $fields = explode('^', $key);\n            foreach ($fields as $key) {\n                $map[$key] = $data[$key];\n            }\n        } elseif (strpos($key, '=')) {\n            parse_str($key, $map);\n        } else {\n            $map[$key] = $data[$field];\n        }\n\n        $pk = strval(isset($rule[3]) ? $rule[3] : $db->getPk());\n        if (isset($rule[2])) {\n            $map[$pk] = ['neq', $rule[2]];\n        } elseif (isset($data[$pk])) {\n            $map[$pk] = ['neq', $data[$pk]];\n        }\n\n        if ($db->where($map)->field($pk)->find()) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 使用行为类验证\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @param array     $data  数据\n     * @return mixed\n     */\n    protected function behavior($value, $rule, $data)\n    {\n        return Hook::exec($rule, '', $data);\n    }\n\n    /**\n     * 使用filter_var方式验证\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function filter($value, $rule)\n    {\n        if (is_string($rule) && strpos($rule, ',')) {\n            list($rule, $param) = explode(',', $rule);\n        } elseif (is_array($rule)) {\n            $param = isset($rule[1]) ? $rule[1] : null;\n            $rule  = $rule[0];\n        } else {\n            $param = null;\n        }\n        return false !== filter_var($value, is_int($rule) ? $rule : filter_id($rule), $param);\n    }\n\n    /**\n     * 验证某个字段等于某个值的时候必须\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @param array     $data  数据\n     * @return bool\n     */\n    protected function requireIf($value, $rule, $data)\n    {\n        list($field, $val) = explode(',', $rule);\n        if ($this->getDataValue($data, $field) == $val) {\n            return !empty($value);\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * 通过回调方法验证某个字段是否必须\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @param array     $data  数据\n     * @return bool\n     */\n    protected function requireCallback($value, $rule, $data)\n    {\n        $result = call_user_func_array($rule, [$value, $data]);\n        if ($result) {\n            return !empty($value);\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * 验证某个字段有值的情况下必须\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @param array     $data  数据\n     * @return bool\n     */\n    protected function requireWith($value, $rule, $data)\n    {\n        $val = $this->getDataValue($data, $rule);\n        if (!empty($val)) {\n            return !empty($value);\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * 验证是否在范围内\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function in($value, $rule)\n    {\n        return in_array($value, is_array($rule) ? $rule : explode(',', $rule));\n    }\n\n    /**\n     * 验证是否不在某个范围\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function notIn($value, $rule)\n    {\n        return !in_array($value, is_array($rule) ? $rule : explode(',', $rule));\n    }\n\n    /**\n     * between验证数据\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function between($value, $rule)\n    {\n        if (is_string($rule)) {\n            $rule = explode(',', $rule);\n        }\n        list($min, $max) = $rule;\n        return $value >= $min && $value <= $max;\n    }\n\n    /**\n     * 使用notbetween验证数据\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function notBetween($value, $rule)\n    {\n        if (is_string($rule)) {\n            $rule = explode(',', $rule);\n        }\n        list($min, $max) = $rule;\n        return $value < $min || $value > $max;\n    }\n\n    /**\n     * 验证数据长度\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function length($value, $rule)\n    {\n        if (is_array($value)) {\n            $length = count($value);\n        } elseif ($value instanceof File) {\n            $length = $value->getSize();\n        } else {\n            $length = mb_strlen((string) $value);\n        }\n\n        if (strpos($rule, ',')) {\n            // 长度区间\n            list($min, $max) = explode(',', $rule);\n            return $length >= $min && $length <= $max;\n        } else {\n            // 指定长度\n            return $length == $rule;\n        }\n    }\n\n    /**\n     * 验证数据最大长度\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function max($value, $rule)\n    {\n        if (is_array($value)) {\n            $length = count($value);\n        } elseif ($value instanceof File) {\n            $length = $value->getSize();\n        } else {\n            $length = mb_strlen((string) $value);\n        }\n        return $length <= $rule;\n    }\n\n    /**\n     * 验证数据最小长度\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function min($value, $rule)\n    {\n        if (is_array($value)) {\n            $length = count($value);\n        } elseif ($value instanceof File) {\n            $length = $value->getSize();\n        } else {\n            $length = mb_strlen((string) $value);\n        }\n        return $length >= $rule;\n    }\n\n    /**\n     * 验证日期\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function after($value, $rule)\n    {\n        return strtotime($value) >= strtotime($rule);\n    }\n\n    /**\n     * 验证日期\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function before($value, $rule)\n    {\n        return strtotime($value) <= strtotime($rule);\n    }\n\n    /**\n     * 验证有效期\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return bool\n     */\n    protected function expire($value, $rule)\n    {\n        if (is_string($rule)) {\n            $rule = explode(',', $rule);\n        }\n        list($start, $end) = $rule;\n        if (!is_numeric($start)) {\n            $start = strtotime($start);\n        }\n\n        if (!is_numeric($end)) {\n            $end = strtotime($end);\n        }\n        return $_SERVER['REQUEST_TIME'] >= $start && $_SERVER['REQUEST_TIME'] <= $end;\n    }\n\n    /**\n     * 验证IP许可\n     * @access protected\n     * @param string    $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return mixed\n     */\n    protected function allowIp($value, $rule)\n    {\n        return in_array($_SERVER['REMOTE_ADDR'], is_array($rule) ? $rule : explode(',', $rule));\n    }\n\n    /**\n     * 验证IP禁用\n     * @access protected\n     * @param string    $value  字段值\n     * @param mixed     $rule  验证规则\n     * @return mixed\n     */\n    protected function denyIp($value, $rule)\n    {\n        return !in_array($_SERVER['REMOTE_ADDR'], is_array($rule) ? $rule : explode(',', $rule));\n    }\n\n    /**\n     * 使用正则验证数据\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则 正则规则或者预定义正则名\n     * @return mixed\n     */\n    protected function regex($value, $rule)\n    {\n        if (isset($this->regex[$rule])) {\n            $rule = $this->regex[$rule];\n        }\n        if (0 !== strpos($rule, '/') && !preg_match('/\\/[imsU]{0,4}$/', $rule)) {\n            // 不是正则表达式则两端补上/\n            $rule = '/^' . $rule . '$/';\n        }\n        return 1 === preg_match($rule, (string) $value);\n    }\n\n    /**\n     * 验证表单令牌\n     * @access protected\n     * @param mixed     $value  字段值\n     * @param mixed     $rule  验证规则\n     * @param array     $data  数据\n     * @return bool\n     */\n    protected function token($value, $rule, $data)\n    {\n        $rule = !empty($rule) ? $rule : '__token__';\n        if (!isset($data[$rule]) || !Session::has($rule)) {\n            // 令牌数据无效\n            return false;\n        }\n\n        // 令牌验证\n        if (isset($data[$rule]) && Session::get($rule) === $data[$rule]) {\n            // 防止重复提交\n            Session::delete($rule); // 验证完成销毁session\n            return true;\n        }\n        // 开启TOKEN重置\n        Session::delete($rule);\n        return false;\n    }\n\n    // 获取错误信息\n    public function getError()\n    {\n        return $this->error;\n    }\n\n    /**\n     * 获取数据值\n     * @access protected\n     * @param array $data 数据\n     * @param string $key 数据标识 支持二维\n     * @return mixed\n     */\n    protected function getDataValue($data, $key)\n    {\n        if (is_numeric($key)) {\n            $value = $key;\n        } elseif (strpos($key, '.')) {\n            // 支持二维数组验证\n            list($name1, $name2) = explode('.', $key);\n            $value               = isset($data[$name1][$name2]) ? $data[$name1][$name2] : null;\n        } else {\n            $value = isset($data[$key]) ? $data[$key] : null;\n        }\n        return $value;\n    }\n\n    /**\n     * 获取验证规则的错误提示信息\n     * @access protected\n     * @param string    $attribute  字段英文名\n     * @param string    $title  字段描述名\n     * @param string    $type  验证规则名称\n     * @param mixed     $rule  验证规则数据\n     * @return string\n     */\n    protected function getRuleMsg($attribute, $title, $type, $rule)\n    {\n        if (isset($this->message[$attribute . '.' . $type])) {\n            $msg = $this->message[$attribute . '.' . $type];\n        } elseif (isset($this->message[$attribute][$type])) {\n            $msg = $this->message[$attribute][$type];\n        } elseif (isset($this->message[$attribute])) {\n            $msg = $this->message[$attribute];\n        } elseif (isset(self::$typeMsg[$type])) {\n            $msg = self::$typeMsg[$type];\n        } else {\n            $msg = $title . '规则错误';\n        }\n\n        if (is_string($msg) && 0 === strpos($msg, '{%')) {\n            $msg = Lang::get(substr($msg, 2, -1));\n        }\n\n        if (is_string($msg) && is_scalar($rule) && false !== strpos($msg, ':')) {\n            // 变量替换\n            if (is_string($rule) && strpos($rule, ',')) {\n                $array = array_pad(explode(',', $rule), 3, '');\n            } else {\n                $array = array_pad([], 3, '');\n            }\n            $msg = str_replace(\n                [':attribute', ':rule', ':1', ':2', ':3'],\n                [$title, (string) $rule, $array[0], $array[1], $array[2]],\n                $msg);\n        }\n        return $msg;\n    }\n\n    /**\n     * 获取数据验证的场景\n     * @access protected\n     * @param string $scene  验证场景\n     * @return array\n     */\n    protected function getScene($scene = '')\n    {\n        if (empty($scene)) {\n            // 读取指定场景\n            $scene = $this->currentScene;\n        }\n\n        if (!empty($scene) && isset($this->scene[$scene])) {\n            // 如果设置了验证适用场景\n            $scene = $this->scene[$scene];\n            if (is_string($scene)) {\n                $scene = explode(',', $scene);\n            }\n        } else {\n            $scene = [];\n        }\n        return $scene;\n    }\n\n    public static function __callStatic($method, $params)\n    {\n        $class = self::make();\n        if (method_exists($class, $method)) {\n            return call_user_func_array([$class, $method], $params);\n        } else {\n            throw new \\BadMethodCallException('method not exists:' . __CLASS__ . '->' . $method);\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/View.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\nclass View\n{\n    // 视图实例\n    protected static $instance;\n    // 模板引擎实例\n    public $engine;\n    // 模板变量\n    protected $data = [];\n    // 用于静态赋值的模板变量\n    protected static $var = [];\n    // 视图输出替换\n    protected $replace = [];\n\n    /**\n     * 构造函数\n     * @access public\n     * @param array $engine  模板引擎参数\n     * @param array $replace  字符串替换参数\n     */\n    public function __construct($engine = [], $replace = [])\n    {\n        // 初始化模板引擎\n        $this->engine((array) $engine);\n        // 基础替换字符串\n        $request = Request::instance();\n        $base    = $request->root();\n        $root    = strpos($base, '.') ? ltrim(dirname($base), DS) : $base;\n        if ('' != $root) {\n            $root = '/' . ltrim($root, '/');\n        }\n        $baseReplace = [\n            '__ROOT__'   => $root,\n            '__URL__'    => $base . '/' . $request->module() . '/' . Loader::parseName($request->controller()),\n            '__STATIC__' => $root . '/static',\n            '__CSS__'    => $root . '/static/css',\n            '__JS__'     => $root . '/static/js',\n        ];\n        $this->replace = array_merge($baseReplace, (array) $replace);\n    }\n\n    /**\n     * 初始化视图\n     * @access public\n     * @param array $engine  模板引擎参数\n     * @param array $replace  字符串替换参数\n     * @return object\n     */\n    public static function instance($engine = [], $replace = [])\n    {\n        if (is_null(self::$instance)) {\n            self::$instance = new self($engine, $replace);\n        }\n        return self::$instance;\n    }\n\n    /**\n     * 模板变量静态赋值\n     * @access public\n     * @param mixed $name  变量名\n     * @param mixed $value 变量值\n     * @return void\n     */\n    public static function share($name, $value = '')\n    {\n        if (is_array($name)) {\n            self::$var = array_merge(self::$var, $name);\n        } else {\n            self::$var[$name] = $value;\n        }\n    }\n\n    /**\n     * 模板变量赋值\n     * @access public\n     * @param mixed $name  变量名\n     * @param mixed $value 变量值\n     * @return $this\n     */\n    public function assign($name, $value = '')\n    {\n        if (is_array($name)) {\n            $this->data = array_merge($this->data, $name);\n        } else {\n            $this->data[$name] = $value;\n        }\n        return $this;\n    }\n\n    /**\n     * 设置当前模板解析的引擎\n     * @access public\n     * @param array|string $options 引擎参数\n     * @return $this\n     */\n    public function engine($options = [])\n    {\n        if (is_string($options)) {\n            $type    = $options;\n            $options = [];\n        } else {\n            $type = !empty($options['type']) ? $options['type'] : 'Think';\n        }\n\n        $class = false !== strpos($type, '\\\\') ? $type : '\\\\think\\\\view\\\\driver\\\\' . ucfirst($type);\n        if (isset($options['type'])) {\n            unset($options['type']);\n        }\n        $this->engine = new $class($options);\n        return $this;\n    }\n\n    /**\n     * 配置模板引擎\n     * @access private\n     * @param string|array  $name 参数名\n     * @param mixed         $value 参数值\n     * @return void\n     */\n    public function config($name, $value = null)\n    {\n        $this->engine->config($name, $value);\n        return $this;\n    }\n\n    /**\n     * 解析和获取模板内容 用于输出\n     * @param string    $template 模板文件名或者内容\n     * @param array     $vars     模板输出变量\n     * @param array     $replace 替换内容\n     * @param array     $config     模板参数\n     * @param bool      $renderContent     是否渲染内容\n     * @return string\n     * @throws Exception\n     */\n    public function fetch($template = '', $vars = [], $replace = [], $config = [], $renderContent = false)\n    {\n        // 模板变量\n        $vars = array_merge(self::$var, $this->data, $vars);\n\n        // 页面缓存\n        ob_start();\n        ob_implicit_flush(0);\n\n        // 渲染输出\n        $method = $renderContent ? 'display' : 'fetch';\n        $this->engine->$method($template, $vars, $config);\n\n        // 获取并清空缓存\n        $content = ob_get_clean();\n        // 内容过滤标签\n        Hook::listen('view_filter', $content);\n        // 允许用户自定义模板的字符串替换\n        $replace = array_merge($this->replace, $replace);\n        if (!empty($replace)) {\n            $content = strtr($content, $replace);\n        }\n        return $content;\n    }\n\n    /**\n     * 视图内容替换\n     * @access public\n     * @param string|array  $content 被替换内容（支持批量替换）\n     * @param string        $replace    替换内容\n     * @return $this\n     */\n    public function replace($content, $replace = '')\n    {\n        if (is_array($content)) {\n            $this->replace = array_merge($this->replace, $content);\n        } else {\n            $this->replace[$content] = $replace;\n        }\n        return $this;\n    }\n\n    /**\n     * 渲染内容输出\n     * @access public\n     * @param string $content 内容\n     * @param array  $vars    模板输出变量\n     * @param array  $replace 替换内容\n     * @param array  $config     模板参数\n     * @return mixed\n     */\n    public function display($content, $vars = [], $replace = [], $config = [])\n    {\n        return $this->fetch($content, $vars, $replace, $config, true);\n    }\n\n    /**\n     * 模板变量赋值\n     * @access public\n     * @param string    $name  变量名\n     * @param mixed     $value 变量值\n     */\n    public function __set($name, $value)\n    {\n        $this->data[$name] = $value;\n    }\n\n    /**\n     * 取得模板显示变量的值\n     * @access protected\n     * @param string $name 模板变量\n     * @return mixed\n     */\n    public function __get($name)\n    {\n        return $this->data[$name];\n    }\n\n    /**\n     * 检测模板变量是否设置\n     * @access public\n     * @param string $name 模板变量名\n     * @return bool\n     */\n    public function __isset($name)\n    {\n        return isset($this->data[$name]);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/cache/Driver.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\cache;\n\n/**\n * 缓存基础类\n */\nabstract class Driver\n{\n    protected $handler = null;\n    protected $options = [];\n    protected $tag;\n\n    /**\n     * 判断缓存是否存在\n     * @access public\n     * @param string $name 缓存变量名\n     * @return bool\n     */\n    abstract public function has($name);\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed  $default 默认值\n     * @return mixed\n     */\n    abstract public function get($name, $default = false);\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param mixed     $value  存储数据\n     * @param int       $expire  有效时间 0为永久\n     * @return boolean\n     */\n    abstract public function set($name, $value, $expire = null);\n\n    /**\n     * 自增缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    abstract public function inc($name, $step = 1);\n\n    /**\n     * 自减缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    abstract public function dec($name, $step = 1);\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    abstract public function rm($name);\n\n    /**\n     * 清除缓存\n     * @access public\n     * @param string $tag 标签名\n     * @return boolean\n     */\n    abstract public function clear($tag = null);\n\n    /**\n     * 获取实际的缓存标识\n     * @access public\n     * @param string $name 缓存名\n     * @return string\n     */\n    protected function getCacheKey($name)\n    {\n        return $this->options['prefix'] . $name;\n    }\n\n    /**\n     * 读取缓存并删除\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function pull($name)\n    {\n        $result = $this->get($name, false);\n        if ($result) {\n            $this->rm($name);\n            return $result;\n        } else {\n            return;\n        }\n    }\n\n    /**\n     * 如果不存在则写入缓存\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param mixed     $value  存储数据\n     * @param int       $expire  有效时间 0为永久\n     * @return mixed\n     */\n    public function remember($name, $value, $expire = null)\n    {\n        if (!$this->has($name)) {\n            if ($value instanceof \\Closure) {\n                $value = call_user_func($value);\n            }\n            $this->set($name, $value, $expire);\n        } else {\n            $value = $this->get($name);\n        }\n        return $value;\n    }\n\n    /**\n     * 缓存标签\n     * @access public\n     * @param string        $name 标签名\n     * @param string|array  $keys 缓存标识\n     * @param bool          $overlay 是否覆盖\n     * @return $this\n     */\n    public function tag($name, $keys = null, $overlay = false)\n    {\n        if (is_null($keys)) {\n            $this->tag = $name;\n        } else {\n            $key = 'tag_' . md5($name);\n            if (is_string($keys)) {\n                $keys = explode(',', $keys);\n            }\n            $keys = array_map([$this, 'getCacheKey'], $keys);\n            if ($overlay) {\n                $value = $keys;\n            } else {\n                $value = array_unique(array_merge($this->getTagItem($name), $keys));\n            }\n            $this->set($key, implode(',', $value));\n        }\n        return $this;\n    }\n\n    /**\n     * 更新标签\n     * @access public\n     * @param string $name 缓存标识\n     * @return void\n     */\n    protected function setTagItem($name)\n    {\n        if ($this->tag) {\n            $key       = 'tag_' . md5($this->tag);\n            $this->tag = null;\n            if ($this->has($key)) {\n                $value   = explode(',', $this->get($key));\n                $value[] = $name;\n                $value   = implode(',', array_unique($value));\n            } else {\n                $value = $name;\n            }\n            $this->set($key, $value);\n        }\n    }\n\n    /**\n     * 获取标签包含的缓存标识\n     * @access public\n     * @param string $tag 缓存标签\n     * @return array\n     */\n    protected function getTagItem($tag)\n    {\n        $key   = 'tag_' . md5($tag);\n        $value = $this->get($key);\n        if ($value) {\n            return explode(',', $value);\n        } else {\n            return [];\n        }\n    }\n\n    /**\n     * 返回句柄对象，可执行其它高级方法\n     *\n     * @access public\n     * @return object\n     */\n    public function handler()\n    {\n        return $this->handler;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/cache/driver/File.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\cache\\driver;\n\nuse think\\cache\\Driver;\n\n/**\n * 文件类型缓存类\n * @author    liu21st <liu21st@gmail.com>\n */\nclass File extends Driver\n{\n    protected $options = [\n        'expire'        => 0,\n        'cache_subdir'  => true,\n        'prefix'        => '',\n        'path'          => CACHE_PATH,\n        'data_compress' => false,\n    ];\n\n    /**\n     * 构造函数\n     * @param array $options\n     */\n    public function __construct($options = [])\n    {\n        if (!empty($options)) {\n            $this->options = array_merge($this->options, $options);\n        }\n        if (substr($this->options['path'], -1) != DS) {\n            $this->options['path'] .= DS;\n        }\n        $this->init();\n    }\n\n    /**\n     * 初始化检查\n     * @access private\n     * @return boolean\n     */\n    private function init()\n    {\n        // 创建项目缓存目录\n        if (!is_dir($this->options['path'])) {\n            if (mkdir($this->options['path'], 0755, true)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 取得变量的存储文件名\n     * @access protected\n     * @param string $name 缓存变量名\n     * @return string\n     */\n    protected function getCacheKey($name)\n    {\n        $name = md5($name);\n        if ($this->options['cache_subdir']) {\n            // 使用子目录\n            $name = substr($name, 0, 2) . DS . substr($name, 2);\n        }\n        if ($this->options['prefix']) {\n            $name = $this->options['prefix'] . DS . $name;\n        }\n        $filename = $this->options['path'] . $name . '.php';\n        $dir      = dirname($filename);\n        if (!is_dir($dir)) {\n            mkdir($dir, 0755, true);\n        }\n        return $filename;\n    }\n\n    /**\n     * 判断缓存是否存在\n     * @access public\n     * @param string $name 缓存变量名\n     * @return bool\n     */\n    public function has($name)\n    {\n        return $this->get($name) ? true : false;\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed  $default 默认值\n     * @return mixed\n     */\n    public function get($name, $default = false)\n    {\n        $filename = $this->getCacheKey($name);\n        if (!is_file($filename)) {\n            return $default;\n        }\n        $content = file_get_contents($filename);\n        if (false !== $content) {\n            $expire = (int) substr($content, 8, 12);\n            if (0 != $expire && $_SERVER['REQUEST_TIME'] > filemtime($filename) + $expire) {\n                //缓存过期删除缓存文件\n                $this->unlink($filename);\n                return $default;\n            }\n            $content = substr($content, 20, -3);\n            if ($this->options['data_compress'] && function_exists('gzcompress')) {\n                //启用数据压缩\n                $content = gzuncompress($content);\n            }\n            $content = unserialize($content);\n            return $content;\n        } else {\n            return $default;\n        }\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param mixed     $value  存储数据\n     * @param int       $expire  有效时间 0为永久\n     * @return boolean\n     */\n    public function set($name, $value, $expire = null)\n    {\n        if (is_null($expire)) {\n            $expire = $this->options['expire'];\n        }\n        $filename = $this->getCacheKey($name);\n        if ($this->tag && !is_file($filename)) {\n            $first = true;\n        }\n        $data = serialize($value);\n        if ($this->options['data_compress'] && function_exists('gzcompress')) {\n            //数据压缩\n            $data = gzcompress($data, 3);\n        }\n        $data   = \"<?php\\n//\" . sprintf('%012d', $expire) . $data . \"\\n?>\";\n        $result = file_put_contents($filename, $data);\n        if ($result) {\n            isset($first) && $this->setTagItem($filename);\n            clearstatcache();\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * 自增缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function inc($name, $step = 1)\n    {\n        if ($this->has($name)) {\n            $value = $this->get($name) + $step;\n        } else {\n            $value = $step;\n        }\n        return $this->set($name, $value, 0) ? $value : false;\n    }\n\n    /**\n     * 自减缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function dec($name, $step = 1)\n    {\n        if ($this->has($name)) {\n            $value = $this->get($name) - $step;\n        } else {\n            $value = $step;\n        }\n        return $this->set($name, $value, 0) ? $value : false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name)\n    {\n        return $this->unlink($this->getCacheKey($name));\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @param string $tag 标签名\n     * @return boolean\n     */\n    public function clear($tag = null)\n    {\n        if ($tag) {\n            // 指定标签清除\n            $keys = $this->getTagItem($tag);\n            foreach ($keys as $key) {\n                $this->unlink($key);\n            }\n            $this->rm('tag_' . md5($tag));\n            return true;\n        }\n        $files = (array) glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DS : '') . '*');\n        foreach ($files as $path) {\n            if (is_dir($path)) {\n                array_map('unlink', glob($path . '/*.php'));\n                rmdir($path);\n            } else {\n                unlink($path);\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 判断文件是否存在后，删除\n     * @param $path\n     * @return bool\n     * @author byron sampson <xiaobo.sun@qq.com>\n     * @return boolean\n     */\n    private function unlink($path)\n    {\n        return is_file($path) && unlink($path);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/cache/driver/Lite.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\cache\\driver;\n\nuse think\\cache\\Driver;\n\n/**\n * 文件类型缓存类\n * @author    liu21st <liu21st@gmail.com>\n */\nclass Lite extends Driver\n{\n    protected $options = [\n        'prefix' => '',\n        'path'   => '',\n        'expire' => 0, // 等于 10*365*24*3600（10年）\n    ];\n\n    /**\n     * 构造函数\n     * @access public\n     *\n     * @param array $options\n     */\n    public function __construct($options = [])\n    {\n        if (!empty($options)) {\n            $this->options = array_merge($this->options, $options);\n        }\n        if (substr($this->options['path'], -1) != DS) {\n            $this->options['path'] .= DS;\n        }\n\n    }\n\n    /**\n     * 取得变量的存储文件名\n     * @access protected\n     * @param string $name 缓存变量名\n     * @return string\n     */\n    protected function getCacheKey($name)\n    {\n        return $this->options['path'] . $this->options['prefix'] . md5($name) . '.php';\n    }\n\n    /**\n     * 判断缓存是否存在\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function has($name)\n    {\n        return $this->get($name) ? true : false;\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed  $default 默认值\n     * @return mixed\n     */\n    public function get($name, $default = false)\n    {\n        $filename = $this->getCacheKey($name);\n        if (is_file($filename)) {\n            // 判断是否过期\n            $mtime = filemtime($filename);\n            if ($mtime < $_SERVER['REQUEST_TIME']) {\n                // 清除已经过期的文件\n                unlink($filename);\n                return $default;\n            }\n            return include $filename;\n        } else {\n            return $default;\n        }\n    }\n\n    /**\n     * 写入缓存\n     * @access   public\n     * @param string    $name  缓存变量名\n     * @param mixed     $value 存储数据\n     * @param int       $expire 有效时间 0为永久\n     * @return bool\n     */\n    public function set($name, $value, $expire = null)\n    {\n        if (is_null($expire)) {\n            $expire = $this->options['expire'];\n        }\n        // 模拟永久\n        if (0 === $expire) {\n            $expire = 10 * 365 * 24 * 3600;\n        }\n        $filename = $this->getCacheKey($name);\n        if ($this->tag && !is_file($filename)) {\n            $first = true;\n        }\n        $ret = file_put_contents($filename, (\"<?php return \" . var_export($value, true) . \";\"));\n        // 通过设置修改时间实现有效期\n        if ($ret) {\n            isset($first) && $this->setTagItem($filename);\n            touch($filename, $_SERVER['REQUEST_TIME'] + $expire);\n        }\n        return $ret;\n    }\n\n    /**\n     * 自增缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function inc($name, $step = 1)\n    {\n        if ($this->has($name)) {\n            $value = $this->get($name) + $step;\n        } else {\n            $value = $step;\n        }\n        return $this->set($name, $value, 0) ? $value : false;\n    }\n\n    /**\n     * 自减缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function dec($name, $step = 1)\n    {\n        if ($this->has($name)) {\n            $value = $this->get($name) - $step;\n        } else {\n            $value = $step;\n        }\n        return $this->set($name, $value, 0) ? $value : false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name)\n    {\n        return unlink($this->getCacheKey($name));\n    }\n\n    /**\n     * 清除缓存\n     * @access   public\n     * @param string $tag 标签名\n     * @return bool\n     */\n    public function clear($tag = null)\n    {\n        if ($tag) {\n            // 指定标签清除\n            $keys = $this->getTagItem($tag);\n            foreach ($keys as $key) {\n                unlink($key);\n            }\n            $this->rm('tag_' . md5($tag));\n            return true;\n        }\n        array_map(\"unlink\", glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DS : '') . '*.php'));\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/cache/driver/Memcache.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\cache\\driver;\n\nuse think\\cache\\Driver;\n\nclass Memcache extends Driver\n{\n    protected $options = [\n        'host'       => '127.0.0.1',\n        'port'       => 11211,\n        'expire'     => 0,\n        'timeout'    => 0, // 超时时间（单位：毫秒）\n        'persistent' => true,\n        'prefix'     => '',\n    ];\n\n    /**\n     * 构造函数\n     * @param array $options 缓存参数\n     * @access public\n     * @throws \\BadFunctionCallException\n     */\n    public function __construct($options = [])\n    {\n        if (!extension_loaded('memcache')) {\n            throw new \\BadFunctionCallException('not support: memcache');\n        }\n        if (!empty($options)) {\n            $this->options = array_merge($this->options, $options);\n        }\n        $this->handler = new \\Memcache;\n        // 支持集群\n        $hosts = explode(',', $this->options['host']);\n        $ports = explode(',', $this->options['port']);\n        if (empty($ports[0])) {\n            $ports[0] = 11211;\n        }\n        // 建立连接\n        foreach ((array) $hosts as $i => $host) {\n            $port = isset($ports[$i]) ? $ports[$i] : $ports[0];\n            $this->options['timeout'] > 0 ?\n            $this->handler->addServer($host, $port, $this->options['persistent'], 1, $this->options['timeout']) :\n            $this->handler->addServer($host, $port, $this->options['persistent'], 1);\n        }\n    }\n\n    /**\n     * 判断缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return bool\n     */\n    public function has($name)\n    {\n        $key = $this->getCacheKey($name);\n        return $this->handler->get($key) ? true : false;\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed  $default 默认值\n     * @return mixed\n     */\n    public function get($name, $default = false)\n    {\n        $result = $this->handler->get($this->getCacheKey($name));\n        return false !== $result ? $result : $default;\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param mixed     $value  存储数据\n     * @param integer   $expire  有效时间（秒）\n     * @return bool\n     */\n    public function set($name, $value, $expire = null)\n    {\n        if (is_null($expire)) {\n            $expire = $this->options['expire'];\n        }\n        if ($this->tag && !$this->has($name)) {\n            $first = true;\n        }\n        $key = $this->getCacheKey($name);\n        if ($this->handler->set($key, $value, 0, $expire)) {\n            isset($first) && $this->setTagItem($key);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 自增缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function inc($name, $step = 1)\n    {\n        $key = $this->getCacheKey($name);\n        if ($this->handler->get($key)) {\n            return $this->handler->increment($key, $step);\n        }\n        return $this->handler->set($key, $step);\n    }\n\n    /**\n     * 自减缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function dec($name, $step = 1)\n    {\n        $key   = $this->getCacheKey($name);\n        $value = $this->handler->get($key) - $step;\n        $res   = $this->handler->set($key, $value);\n        if (!$res) {\n            return false;\n        } else {\n            return $value;\n        }\n    }\n\n    /**\n     * 删除缓存\n     * @param    string  $name 缓存变量名\n     * @param bool|false $ttl\n     * @return bool\n     */\n    public function rm($name, $ttl = false)\n    {\n        $key = $this->getCacheKey($name);\n        return false === $ttl ?\n        $this->handler->delete($key) :\n        $this->handler->delete($key, $ttl);\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @param string $tag 标签名\n     * @return bool\n     */\n    public function clear($tag = null)\n    {\n        if ($tag) {\n            // 指定标签清除\n            $keys = $this->getTagItem($tag);\n            foreach ($keys as $key) {\n                $this->handler->delete($key);\n            }\n            $this->rm('tag_' . md5($tag));\n            return true;\n        }\n        return $this->handler->flush();\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/cache/driver/Memcached.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\cache\\driver;\n\nuse think\\cache\\Driver;\n\nclass Memcached extends Driver\n{\n    protected $options = [\n        'host'     => '127.0.0.1',\n        'port'     => 11211,\n        'expire'   => 0,\n        'timeout'  => 0, // 超时时间（单位：毫秒）\n        'prefix'   => '',\n        'username' => '', //账号\n        'password' => '', //密码\n        'option'   => [],\n    ];\n\n    /**\n     * 构造函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options = [])\n    {\n        if (!extension_loaded('memcached')) {\n            throw new \\BadFunctionCallException('not support: memcached');\n        }\n        if (!empty($options)) {\n            $this->options = array_merge($this->options, $options);\n        }\n        $this->handler = new \\Memcached;\n        if (!empty($this->options['option'])) {\n            $this->handler->setOptions($this->options['option']);\n        }\n        // 设置连接超时时间（单位：毫秒）\n        if ($this->options['timeout'] > 0) {\n            $this->handler->setOption(\\Memcached::OPT_CONNECT_TIMEOUT, $this->options['timeout']);\n        }\n        // 支持集群\n        $hosts = explode(',', $this->options['host']);\n        $ports = explode(',', $this->options['port']);\n        if (empty($ports[0])) {\n            $ports[0] = 11211;\n        }\n        // 建立连接\n        $servers = [];\n        foreach ((array) $hosts as $i => $host) {\n            $servers[] = [$host, (isset($ports[$i]) ? $ports[$i] : $ports[0]), 1];\n        }\n        $this->handler->addServers($servers);\n        if ('' != $this->options['username']) {\n            $this->handler->setOption(\\Memcached::OPT_BINARY_PROTOCOL, true);\n            $this->handler->setSaslAuthData($this->options['username'], $this->options['password']);\n        }\n    }\n\n    /**\n     * 判断缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return bool\n     */\n    public function has($name)\n    {\n        $key = $this->getCacheKey($name);\n        return $this->handler->get($key) ? true : false;\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed  $default 默认值\n     * @return mixed\n     */\n    public function get($name, $default = false)\n    {\n        $result = $this->handler->get($this->getCacheKey($name));\n        return false !== $result ? $result : $default;\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param mixed     $value  存储数据\n     * @param integer   $expire  有效时间（秒）\n     * @return bool\n     */\n    public function set($name, $value, $expire = null)\n    {\n        if (is_null($expire)) {\n            $expire = $this->options['expire'];\n        }\n        if ($this->tag && !$this->has($name)) {\n            $first = true;\n        }\n        $key    = $this->getCacheKey($name);\n        $expire = 0 == $expire ? 0 : $_SERVER['REQUEST_TIME'] + $expire;\n        if ($this->handler->set($key, $value, $expire)) {\n            isset($first) && $this->setTagItem($key);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 自增缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function inc($name, $step = 1)\n    {\n        $key = $this->getCacheKey($name);\n        if ($this->handler->get($key)) {\n            return $this->handler->increment($key, $step);\n        }\n        return $this->handler->set($key, $step);\n    }\n\n    /**\n     * 自减缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function dec($name, $step = 1)\n    {\n        $key   = $this->getCacheKey($name);\n        $value = $this->handler->get($key) - $step;\n        $res   = $this->handler->set($key, $value);\n        if (!$res) {\n            return false;\n        } else {\n            return $value;\n        }\n    }\n\n    /**\n     * 删除缓存\n     * @param    string  $name 缓存变量名\n     * @param bool|false $ttl\n     * @return bool\n     */\n    public function rm($name, $ttl = false)\n    {\n        $key = $this->getCacheKey($name);\n        return false === $ttl ?\n        $this->handler->delete($key) :\n        $this->handler->delete($key, $ttl);\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @param string $tag 标签名\n     * @return bool\n     */\n    public function clear($tag = null)\n    {\n        if ($tag) {\n            // 指定标签清除\n            $keys = $this->getTagItem($tag);\n            $this->handler->deleteMulti($keys);\n            $this->rm('tag_' . md5($tag));\n            return true;\n        }\n        return $this->handler->flush();\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/cache/driver/Redis.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\cache\\driver;\n\nuse think\\cache\\Driver;\n\n/**\n * Redis缓存驱动，适合单机部署、有前端代理实现高可用的场景，性能最好\n * 有需要在业务层实现读写分离、或者使用RedisCluster的需求，请使用Redisd驱动\n *\n * 要求安装phpredis扩展：https://github.com/nicolasff/phpredis\n * @author    尘缘 <130775@qq.com>\n */\nclass Redis extends Driver\n{\n    protected $options = [\n        'host'       => '127.0.0.1',\n        'port'       => 6379,\n        'password'   => '',\n        'select'     => 0,\n        'timeout'    => 0,\n        'expire'     => 0,\n        'persistent' => false,\n        'prefix'     => '',\n    ];\n\n    /**\n     * 构造函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options = [])\n    {\n        if (!extension_loaded('redis')) {\n            throw new \\BadFunctionCallException('not support: redis');\n        }\n        if (!empty($options)) {\n            $this->options = array_merge($this->options, $options);\n        }\n        $func          = $this->options['persistent'] ? 'pconnect' : 'connect';\n        $this->handler = new \\Redis;\n        $this->handler->$func($this->options['host'], $this->options['port'], $this->options['timeout']);\n\n        if ('' != $this->options['password']) {\n            $this->handler->auth($this->options['password']);\n        }\n\n        if (0 != $this->options['select']) {\n            $this->handler->select($this->options['select']);\n        }\n    }\n\n    /**\n     * 判断缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return bool\n     */\n    public function has($name)\n    {\n        return $this->handler->get($this->getCacheKey($name)) ? true : false;\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed  $default 默认值\n     * @return mixed\n     */\n    public function get($name, $default = false)\n    {\n        $value = $this->handler->get($this->getCacheKey($name));\n        if (is_null($value)) {\n            return $default;\n        }\n        $jsonData = json_decode($value, true);\n        // 检测是否为JSON数据 true 返回JSON解析数组, false返回源数据 byron sampson<xiaobo.sun@qq.com>\n        return (null === $jsonData) ? $value : $jsonData;\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param mixed     $value  存储数据\n     * @param integer   $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value, $expire = null)\n    {\n        if (is_null($expire)) {\n            $expire = $this->options['expire'];\n        }\n        if ($this->tag && !$this->has($name)) {\n            $first = true;\n        }\n        $key = $this->getCacheKey($name);\n        //对数组/对象数据进行缓存处理，保证数据完整性  byron sampson<xiaobo.sun@qq.com>\n        $value = (is_object($value) || is_array($value)) ? json_encode($value) : $value;\n        if (is_int($expire) && $expire) {\n            $result = $this->handler->setex($key, $expire, $value);\n        } else {\n            $result = $this->handler->set($key, $value);\n        }\n        isset($first) && $this->setTagItem($key);\n        return $result;\n    }\n\n    /**\n     * 自增缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function inc($name, $step = 1)\n    {\n        $key = $this->getCacheKey($name);\n        return $this->handler->incrby($key, $step);\n    }\n\n    /**\n     * 自减缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function dec($name, $step = 1)\n    {\n        $key = $this->getCacheKey($name);\n        return $this->handler->decrby($key, $step);\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name)\n    {\n        return $this->handler->delete($this->getCacheKey($name));\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @param string $tag 标签名\n     * @return boolean\n     */\n    public function clear($tag = null)\n    {\n        if ($tag) {\n            // 指定标签清除\n            $keys = $this->getTagItem($tag);\n            foreach ($keys as $key) {\n                $this->handler->delete($key);\n            }\n            $this->rm('tag_' . md5($tag));\n            return true;\n        }\n        return $this->handler->flushDB();\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/cache/driver/Sqlite.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\cache\\driver;\n\nuse think\\cache\\Driver;\n\n/**\n * Sqlite缓存驱动\n * @author    liu21st <liu21st@gmail.com>\n */\nclass Sqlite extends Driver\n{\n    protected $options = [\n        'db'         => ':memory:',\n        'table'      => 'sharedmemory',\n        'prefix'     => '',\n        'expire'     => 0,\n        'persistent' => false,\n    ];\n\n    /**\n     * 构造函数\n     * @param array $options 缓存参数\n     * @throws \\BadFunctionCallException\n     * @access public\n     */\n    public function __construct($options = [])\n    {\n        if (!extension_loaded('sqlite')) {\n            throw new \\BadFunctionCallException('not support: sqlite');\n        }\n        if (!empty($options)) {\n            $this->options = array_merge($this->options, $options);\n        }\n        $func          = $this->options['persistent'] ? 'sqlite_popen' : 'sqlite_open';\n        $this->handler = $func($this->options['db']);\n    }\n\n    /**\n     * 获取实际的缓存标识\n     * @access public\n     * @param string $name 缓存名\n     * @return string\n     */\n    protected function getCacheKey($name)\n    {\n        return $this->options['prefix'] . sqlite_escape_string($name);\n    }\n\n    /**\n     * 判断缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return bool\n     */\n    public function has($name)\n    {\n        $name   = $this->getCacheKey($name);\n        $sql    = 'SELECT value FROM ' . $this->options['table'] . ' WHERE var=\\'' . $name . '\\' AND (expire=0 OR expire >' . $_SERVER['REQUEST_TIME'] . ') LIMIT 1';\n        $result = sqlite_query($this->handler, $sql);\n        return sqlite_num_rows($result);\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed  $default 默认值\n     * @return mixed\n     */\n    public function get($name, $default = false)\n    {\n        $name   = $this->getCacheKey($name);\n        $sql    = 'SELECT value FROM ' . $this->options['table'] . ' WHERE var=\\'' . $name . '\\' AND (expire=0 OR expire >' . $_SERVER['REQUEST_TIME'] . ') LIMIT 1';\n        $result = sqlite_query($this->handler, $sql);\n        if (sqlite_num_rows($result)) {\n            $content = sqlite_fetch_single($result);\n            if (function_exists('gzcompress')) {\n                //启用数据压缩\n                $content = gzuncompress($content);\n            }\n            return unserialize($content);\n        }\n        return $default;\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param mixed     $value  存储数据\n     * @param integer   $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value, $expire = null)\n    {\n        $name  = $this->getCacheKey($name);\n        $value = sqlite_escape_string(serialize($value));\n        if (is_null($expire)) {\n            $expire = $this->options['expire'];\n        }\n        $expire = (0 == $expire) ? 0 : ($_SERVER['REQUEST_TIME'] + $expire); //缓存有效期为0表示永久缓存\n        if (function_exists('gzcompress')) {\n            //数据压缩\n            $value = gzcompress($value, 3);\n        }\n        if ($this->tag) {\n            $tag       = $this->tag;\n            $this->tag = null;\n        } else {\n            $tag = '';\n        }\n        $sql = 'REPLACE INTO ' . $this->options['table'] . ' (var, value, expire, tag) VALUES (\\'' . $name . '\\', \\'' . $value . '\\', \\'' . $expire . '\\', \\'' . $tag . '\\')';\n        if (sqlite_query($this->handler, $sql)) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 自增缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function inc($name, $step = 1)\n    {\n        if ($this->has($name)) {\n            $value = $this->get($name) + $step;\n        } else {\n            $value = $step;\n        }\n        return $this->set($name, $value, 0) ? $value : false;\n    }\n\n    /**\n     * 自减缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function dec($name, $step = 1)\n    {\n        if ($this->has($name)) {\n            $value = $this->get($name) - $step;\n        } else {\n            $value = $step;\n        }\n        return $this->set($name, $value, 0) ? $value : false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name)\n    {\n        $name = $this->getCacheKey($name);\n        $sql  = 'DELETE FROM ' . $this->options['table'] . ' WHERE var=\\'' . $name . '\\'';\n        sqlite_query($this->handler, $sql);\n        return true;\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @param string $tag 标签名\n     * @return boolean\n     */\n    public function clear($tag = null)\n    {\n        if ($tag) {\n            $name = sqlite_escape_string($tag);\n            $sql  = 'DELETE FROM ' . $this->options['table'] . ' WHERE tag=\\'' . $name . '\\'';\n            sqlite_query($this->handler, $sql);\n            return true;\n        }\n        $sql = 'DELETE FROM ' . $this->options['table'];\n        sqlite_query($this->handler, $sql);\n        return true;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/cache/driver/Wincache.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\cache\\driver;\n\nuse think\\cache\\Driver;\n\n/**\n * Wincache缓存驱动\n * @author    liu21st <liu21st@gmail.com>\n */\nclass Wincache extends Driver\n{\n    protected $options = [\n        'prefix' => '',\n        'expire' => 0,\n    ];\n\n    /**\n     * 构造函数\n     * @param array $options 缓存参数\n     * @throws \\BadFunctionCallException\n     * @access public\n     */\n    public function __construct($options = [])\n    {\n        if (!function_exists('wincache_ucache_info')) {\n            throw new \\BadFunctionCallException('not support: WinCache');\n        }\n        if (!empty($options)) {\n            $this->options = array_merge($this->options, $options);\n        }\n    }\n\n    /**\n     * 判断缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return bool\n     */\n    public function has($name)\n    {\n        $key = $this->getCacheKey($name);\n        return wincache_ucache_exists($key);\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed  $default 默认值\n     * @return mixed\n     */\n    public function get($name, $default = false)\n    {\n        $key = $this->getCacheKey($name);\n        return wincache_ucache_exists($key) ? wincache_ucache_get($key) : $default;\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param mixed     $value  存储数据\n     * @param integer   $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value, $expire = null)\n    {\n        if (is_null($expire)) {\n            $expire = $this->options['expire'];\n        }\n        $key = $this->getCacheKey($name);\n        if ($this->tag && !$this->has($name)) {\n            $first = true;\n        }\n        if (wincache_ucache_set($key, $value, $expire)) {\n            isset($first) && $this->setTagItem($key);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 自增缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function inc($name, $step = 1)\n    {\n        $key = $this->getCacheKey($name);\n        return wincache_ucache_inc($key, $step);\n    }\n\n    /**\n     * 自减缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function dec($name, $step = 1)\n    {\n        $key = $this->getCacheKey($name);\n        return wincache_ucache_dec($key, $step);\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name)\n    {\n        return wincache_ucache_delete($this->getCacheKey($name));\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @param string $tag 标签名\n     * @return boolean\n     */\n    public function clear($tag = null)\n    {\n        if ($tag) {\n            $keys = $this->getTagItem($tag);\n            foreach ($keys as $key) {\n                wincache_ucache_delete($key);\n            }\n            $this->rm('tag_' . md5($tag));\n            return true;\n        } else {\n            return wincache_ucache_clear();\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/cache/driver/Xcache.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\cache\\driver;\n\nuse think\\cache\\Driver;\n\n/**\n * Xcache缓存驱动\n * @author    liu21st <liu21st@gmail.com>\n */\nclass Xcache extends Driver\n{\n    protected $options = [\n        'prefix' => '',\n        'expire' => 0,\n    ];\n\n    /**\n     * 构造函数\n     * @param array $options 缓存参数\n     * @access public\n     * @throws \\BadFunctionCallException\n     */\n    public function __construct($options = [])\n    {\n        if (!function_exists('xcache_info')) {\n            throw new \\BadFunctionCallException('not support: Xcache');\n        }\n        if (!empty($options)) {\n            $this->options = array_merge($this->options, $options);\n        }\n    }\n\n    /**\n     * 判断缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return bool\n     */\n    public function has($name)\n    {\n        $key = $this->getCacheKey($name);\n        return xcache_isset($key);\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed  $default 默认值\n     * @return mixed\n     */\n    public function get($name, $default = false)\n    {\n        $key = $this->getCacheKey($name);\n        return xcache_isset($key) ? xcache_get($key) : $default;\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param mixed     $value  存储数据\n     * @param integer   $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value, $expire = null)\n    {\n        if (is_null($expire)) {\n            $expire = $this->options['expire'];\n        }\n        if ($this->tag && !$this->has($name)) {\n            $first = true;\n        }\n        $key = $this->getCacheKey($name);\n        if (xcache_set($key, $value, $expire)) {\n            isset($first) && $this->setTagItem($key);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 自增缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function inc($name, $step = 1)\n    {\n        $key = $this->getCacheKey($name);\n        return xcache_inc($key, $step);\n    }\n\n    /**\n     * 自减缓存（针对数值缓存）\n     * @access public\n     * @param string    $name 缓存变量名\n     * @param int       $step 步长\n     * @return false|int\n     */\n    public function dec($name, $step = 1)\n    {\n        $key = $this->getCacheKey($name);\n        return xcache_dec($key, $step);\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name)\n    {\n        return xcache_unset($this->getCacheKey($name));\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @param string $tag 标签名\n     * @return boolean\n     */\n    public function clear($tag = null)\n    {\n        if ($tag) {\n            // 指定标签清除\n            $keys = $this->getTagItem($tag);\n            foreach ($keys as $key) {\n                xcache_unset($key);\n            }\n            $this->rm('tag_' . md5($tag));\n            return true;\n        }\n        if (function_exists('xcache_unset_by_prefix')) {\n            return xcache_unset_by_prefix($this->options['prefix']);\n        } else {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/config/driver/Ini.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\config\\driver;\n\nclass Ini\n{\n    public function parse($config)\n    {\n        if (is_file($config)) {\n            return parse_ini_file($config, true);\n        } else {\n            return parse_ini_string($config, true);\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/config/driver/Json.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\config\\driver;\n\nclass Json\n{\n    public function parse($config)\n    {\n        if (is_file($config)) {\n            $config = file_get_contents($config);\n        }\n        $result = json_decode($config, true);\n        return $result;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/config/driver/Xml.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\config\\driver;\n\nclass Xml\n{\n    public function parse($config)\n    {\n        if (is_file($config)) {\n            $content = simplexml_load_file($config);\n        } else {\n            $content = simplexml_load_string($config);\n        }\n        $result = (array) $content;\n        foreach ($result as $key => $val) {\n            if (is_object($val)) {\n                $result[$key] = (array) $val;\n            }\n        }\n        return $result;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/Command.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console;\n\nuse think\\Console;\nuse think\\console\\input\\Argument;\nuse think\\console\\input\\Definition;\nuse think\\console\\input\\Option;\n\nclass Command\n{\n\n    /** @var  Console */\n    private $console;\n    private $name;\n    private $aliases = [];\n    private $definition;\n    private $help;\n    private $description;\n    private $ignoreValidationErrors          = false;\n    private $consoleDefinitionMerged         = false;\n    private $consoleDefinitionMergedWithArgs = false;\n    private $code;\n    private $synopsis = [];\n    private $usages   = [];\n\n    /** @var  Input */\n    protected $input;\n\n    /** @var  Output */\n    protected $output;\n\n    /**\n     * 构造方法\n     * @param string|null $name 命令名称,如果没有设置则比如在 configure() 里设置\n     * @throws \\LogicException\n     * @api\n     */\n    public function __construct($name = null)\n    {\n        $this->definition = new Definition();\n\n        if (null !== $name) {\n            $this->setName($name);\n        }\n\n        $this->configure();\n\n        if (!$this->name) {\n            throw new \\LogicException(sprintf('The command defined in \"%s\" cannot have an empty name.', get_class($this)));\n        }\n    }\n\n    /**\n     * 忽略验证错误\n     */\n    public function ignoreValidationErrors()\n    {\n        $this->ignoreValidationErrors = true;\n    }\n\n    /**\n     * 设置控制台\n     * @param Console $console\n     */\n    public function setConsole(Console $console = null)\n    {\n        $this->console = $console;\n    }\n\n    /**\n     * 获取控制台\n     * @return Console\n     * @api\n     */\n    public function getConsole()\n    {\n        return $this->console;\n    }\n\n    /**\n     * 是否有效\n     * @return bool\n     */\n    public function isEnabled()\n    {\n        return true;\n    }\n\n    /**\n     * 配置指令\n     */\n    protected function configure()\n    {\n    }\n\n    /**\n     * 执行指令\n     * @param Input  $input\n     * @param Output $output\n     * @return null|int\n     * @throws \\LogicException\n     * @see setCode()\n     */\n    protected function execute(Input $input, Output $output)\n    {\n        throw new \\LogicException('You must override the execute() method in the concrete command class.');\n    }\n\n    /**\n     * 用户验证\n     * @param Input  $input\n     * @param Output $output\n     */\n    protected function interact(Input $input, Output $output)\n    {\n    }\n\n    /**\n     * 初始化\n     * @param Input  $input  An InputInterface instance\n     * @param Output $output An OutputInterface instance\n     */\n    protected function initialize(Input $input, Output $output)\n    {\n    }\n\n    /**\n     * 执行\n     * @param Input  $input\n     * @param Output $output\n     * @return int\n     * @throws \\Exception\n     * @see setCode()\n     * @see execute()\n     */\n    public function run(Input $input, Output $output)\n    {\n        $this->input  = $input;\n        $this->output = $output;\n\n        $this->getSynopsis(true);\n        $this->getSynopsis(false);\n\n        $this->mergeConsoleDefinition();\n\n        try {\n            $input->bind($this->definition);\n        } catch (\\Exception $e) {\n            if (!$this->ignoreValidationErrors) {\n                throw $e;\n            }\n        }\n\n        $this->initialize($input, $output);\n\n        if ($input->isInteractive()) {\n            $this->interact($input, $output);\n        }\n\n        $input->validate();\n\n        if ($this->code) {\n            $statusCode = call_user_func($this->code, $input, $output);\n        } else {\n            $statusCode = $this->execute($input, $output);\n        }\n\n        return is_numeric($statusCode) ? (int) $statusCode : 0;\n    }\n\n    /**\n     * 设置执行代码\n     * @param callable $code callable(InputInterface $input, OutputInterface $output)\n     * @return Command\n     * @throws \\InvalidArgumentException\n     * @see execute()\n     */\n    public function setCode(callable $code)\n    {\n        if (!is_callable($code)) {\n            throw new \\InvalidArgumentException('Invalid callable provided to Command::setCode.');\n        }\n\n        if (PHP_VERSION_ID >= 50400 && $code instanceof \\Closure) {\n            $r = new \\ReflectionFunction($code);\n            if (null === $r->getClosureThis()) {\n                $code = \\Closure::bind($code, $this);\n            }\n        }\n\n        $this->code = $code;\n\n        return $this;\n    }\n\n    /**\n     * 合并参数定义\n     * @param bool $mergeArgs\n     */\n    public function mergeConsoleDefinition($mergeArgs = true)\n    {\n        if (null === $this->console\n            || (true === $this->consoleDefinitionMerged\n                && ($this->consoleDefinitionMergedWithArgs || !$mergeArgs))\n        ) {\n            return;\n        }\n\n        if ($mergeArgs) {\n            $currentArguments = $this->definition->getArguments();\n            $this->definition->setArguments($this->console->getDefinition()->getArguments());\n            $this->definition->addArguments($currentArguments);\n        }\n\n        $this->definition->addOptions($this->console->getDefinition()->getOptions());\n\n        $this->consoleDefinitionMerged = true;\n        if ($mergeArgs) {\n            $this->consoleDefinitionMergedWithArgs = true;\n        }\n    }\n\n    /**\n     * 设置参数定义\n     * @param array|Definition $definition\n     * @return Command\n     * @api\n     */\n    public function setDefinition($definition)\n    {\n        if ($definition instanceof Definition) {\n            $this->definition = $definition;\n        } else {\n            $this->definition->setDefinition($definition);\n        }\n\n        $this->consoleDefinitionMerged = false;\n\n        return $this;\n    }\n\n    /**\n     * 获取参数定义\n     * @return Definition\n     * @api\n     */\n    public function getDefinition()\n    {\n        return $this->definition;\n    }\n\n    /**\n     * 获取当前指令的参数定义\n     * @return Definition\n     */\n    public function getNativeDefinition()\n    {\n        return $this->getDefinition();\n    }\n\n    /**\n     * 添加参数\n     * @param string $name        名称\n     * @param int    $mode        类型\n     * @param string $description 描述\n     * @param mixed  $default     默认值\n     * @return Command\n     */\n    public function addArgument($name, $mode = null, $description = '', $default = null)\n    {\n        $this->definition->addArgument(new Argument($name, $mode, $description, $default));\n\n        return $this;\n    }\n\n    /**\n     * 添加选项\n     * @param string $name        选项名称\n     * @param string $shortcut    别名\n     * @param int    $mode        类型\n     * @param string $description 描述\n     * @param mixed  $default     默认值\n     * @return Command\n     */\n    public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)\n    {\n        $this->definition->addOption(new Option($name, $shortcut, $mode, $description, $default));\n\n        return $this;\n    }\n\n    /**\n     * 设置指令名称\n     * @param string $name\n     * @return Command\n     * @throws \\InvalidArgumentException\n     */\n    public function setName($name)\n    {\n        $this->validateName($name);\n\n        $this->name = $name;\n\n        return $this;\n    }\n\n    /**\n     * 获取指令名称\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * 设置描述\n     * @param string $description\n     * @return Command\n     */\n    public function setDescription($description)\n    {\n        $this->description = $description;\n\n        return $this;\n    }\n\n    /**\n     *  获取描述\n     * @return string\n     */\n    public function getDescription()\n    {\n        return $this->description;\n    }\n\n    /**\n     * 设置帮助信息\n     * @param string $help\n     * @return Command\n     */\n    public function setHelp($help)\n    {\n        $this->help = $help;\n\n        return $this;\n    }\n\n    /**\n     * 获取帮助信息\n     * @return string\n     */\n    public function getHelp()\n    {\n        return $this->help;\n    }\n\n    /**\n     * 描述信息\n     * @return string\n     */\n    public function getProcessedHelp()\n    {\n        $name = $this->name;\n\n        $placeholders = [\n            '%command.name%',\n            '%command.full_name%',\n        ];\n        $replacements = [\n            $name,\n            $_SERVER['PHP_SELF'] . ' ' . $name,\n        ];\n\n        return str_replace($placeholders, $replacements, $this->getHelp());\n    }\n\n    /**\n     * 设置别名\n     * @param string[] $aliases\n     * @return Command\n     * @throws \\InvalidArgumentException\n     */\n    public function setAliases($aliases)\n    {\n        if (!is_array($aliases) && !$aliases instanceof \\Traversable) {\n            throw new \\InvalidArgumentException('$aliases must be an array or an instance of \\Traversable');\n        }\n\n        foreach ($aliases as $alias) {\n            $this->validateName($alias);\n        }\n\n        $this->aliases = $aliases;\n\n        return $this;\n    }\n\n    /**\n     * 获取别名\n     * @return array\n     */\n    public function getAliases()\n    {\n        return $this->aliases;\n    }\n\n    /**\n     * 获取简介\n     * @param bool $short 是否简单的\n     * @return string\n     */\n    public function getSynopsis($short = false)\n    {\n        $key = $short ? 'short' : 'long';\n\n        if (!isset($this->synopsis[$key])) {\n            $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));\n        }\n\n        return $this->synopsis[$key];\n    }\n\n    /**\n     * 添加用法介绍\n     * @param string $usage\n     * @return $this\n     */\n    public function addUsage($usage)\n    {\n        if (0 !== strpos($usage, $this->name)) {\n            $usage = sprintf('%s %s', $this->name, $usage);\n        }\n\n        $this->usages[] = $usage;\n\n        return $this;\n    }\n\n    /**\n     * 获取用法介绍\n     * @return array\n     */\n    public function getUsages()\n    {\n        return $this->usages;\n    }\n\n    /**\n     * 验证指令名称\n     * @param string $name\n     * @throws \\InvalidArgumentException\n     */\n    private function validateName($name)\n    {\n        if (!preg_match('/^[^\\:]++(\\:[^\\:]++)*$/', $name)) {\n            throw new \\InvalidArgumentException(sprintf('Command name \"%s\" is invalid.', $name));\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/Input.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console;\n\nuse think\\console\\input\\Argument;\nuse think\\console\\input\\Definition;\nuse think\\console\\input\\Option;\n\nclass Input\n{\n\n    /**\n     * @var Definition\n     */\n    protected $definition;\n\n    /**\n     * @var Option[]\n     */\n    protected $options = [];\n\n    /**\n     * @var Argument[]\n     */\n    protected $arguments = [];\n\n    protected $interactive = true;\n\n    private $tokens;\n    private $parsed;\n\n    public function __construct($argv = null)\n    {\n        if (null === $argv) {\n            $argv = $_SERVER['argv'];\n            // 去除命令名\n            array_shift($argv);\n        }\n\n        $this->tokens = $argv;\n\n        $this->definition = new Definition();\n    }\n\n    protected function setTokens(array $tokens)\n    {\n        $this->tokens = $tokens;\n    }\n\n    /**\n     * 绑定实例\n     * @param Definition $definition A InputDefinition instance\n     */\n    public function bind(Definition $definition)\n    {\n        $this->arguments  = [];\n        $this->options    = [];\n        $this->definition = $definition;\n\n        $this->parse();\n    }\n\n    /**\n     * 解析参数\n     */\n    protected function parse()\n    {\n        $parseOptions = true;\n        $this->parsed = $this->tokens;\n        while (null !== $token = array_shift($this->parsed)) {\n            if ($parseOptions && '' == $token) {\n                $this->parseArgument($token);\n            } elseif ($parseOptions && '--' == $token) {\n                $parseOptions = false;\n            } elseif ($parseOptions && 0 === strpos($token, '--')) {\n                $this->parseLongOption($token);\n            } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {\n                $this->parseShortOption($token);\n            } else {\n                $this->parseArgument($token);\n            }\n        }\n    }\n\n    /**\n     * 解析短选项\n     * @param string $token 当前的指令.\n     */\n    private function parseShortOption($token)\n    {\n        $name = substr($token, 1);\n\n        if (strlen($name) > 1) {\n            if ($this->definition->hasShortcut($name[0])\n                && $this->definition->getOptionForShortcut($name[0])->acceptValue()\n            ) {\n                $this->addShortOption($name[0], substr($name, 1));\n            } else {\n                $this->parseShortOptionSet($name);\n            }\n        } else {\n            $this->addShortOption($name, null);\n        }\n    }\n\n    /**\n     * 解析短选项\n     * @param string $name 当前指令\n     * @throws \\RuntimeException\n     */\n    private function parseShortOptionSet($name)\n    {\n        $len = strlen($name);\n        for ($i = 0; $i < $len; ++$i) {\n            if (!$this->definition->hasShortcut($name[$i])) {\n                throw new \\RuntimeException(sprintf('The \"-%s\" option does not exist.', $name[$i]));\n            }\n\n            $option = $this->definition->getOptionForShortcut($name[$i]);\n            if ($option->acceptValue()) {\n                $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));\n\n                break;\n            } else {\n                $this->addLongOption($option->getName(), null);\n            }\n        }\n    }\n\n    /**\n     * 解析完整选项\n     * @param string $token 当前指令\n     */\n    private function parseLongOption($token)\n    {\n        $name = substr($token, 2);\n\n        if (false !== $pos = strpos($name, '=')) {\n            $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));\n        } else {\n            $this->addLongOption($name, null);\n        }\n    }\n\n    /**\n     * 解析参数\n     * @param string $token 当前指令\n     * @throws \\RuntimeException\n     */\n    private function parseArgument($token)\n    {\n        $c = count($this->arguments);\n\n        if ($this->definition->hasArgument($c)) {\n            $arg = $this->definition->getArgument($c);\n\n            $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;\n\n        } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {\n            $arg = $this->definition->getArgument($c - 1);\n\n            $this->arguments[$arg->getName()][] = $token;\n        } else {\n            throw new \\RuntimeException('Too many arguments.');\n        }\n    }\n\n    /**\n     * 添加一个短选项的值\n     * @param string $shortcut 短名称\n     * @param mixed  $value    值\n     * @throws \\RuntimeException\n     */\n    private function addShortOption($shortcut, $value)\n    {\n        if (!$this->definition->hasShortcut($shortcut)) {\n            throw new \\RuntimeException(sprintf('The \"-%s\" option does not exist.', $shortcut));\n        }\n\n        $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);\n    }\n\n    /**\n     * 添加一个完整选项的值\n     * @param string $name  选项名\n     * @param mixed  $value 值\n     * @throws \\RuntimeException\n     */\n    private function addLongOption($name, $value)\n    {\n        if (!$this->definition->hasOption($name)) {\n            throw new \\RuntimeException(sprintf('The \"--%s\" option does not exist.', $name));\n        }\n\n        $option = $this->definition->getOption($name);\n\n        if (false === $value) {\n            $value = null;\n        }\n\n        if (null !== $value && !$option->acceptValue()) {\n            throw new \\RuntimeException(sprintf('The \"--%s\" option does not accept a value.', $name, $value));\n        }\n\n        if (null === $value && $option->acceptValue() && count($this->parsed)) {\n            $next = array_shift($this->parsed);\n            if (isset($next[0]) && '-' !== $next[0]) {\n                $value = $next;\n            } elseif (empty($next)) {\n                $value = '';\n            } else {\n                array_unshift($this->parsed, $next);\n            }\n        }\n\n        if (null === $value) {\n            if ($option->isValueRequired()) {\n                throw new \\RuntimeException(sprintf('The \"--%s\" option requires a value.', $name));\n            }\n\n            if (!$option->isArray()) {\n                $value = $option->isValueOptional() ? $option->getDefault() : true;\n            }\n        }\n\n        if ($option->isArray()) {\n            $this->options[$name][] = $value;\n        } else {\n            $this->options[$name] = $value;\n        }\n    }\n\n    /**\n     * 获取第一个参数\n     * @return string|null\n     */\n    public function getFirstArgument()\n    {\n        foreach ($this->tokens as $token) {\n            if ($token && '-' === $token[0]) {\n                continue;\n            }\n\n            return $token;\n        }\n        return;\n    }\n\n    /**\n     * 检查原始参数是否包含某个值\n     * @param string|array $values 需要检查的值\n     * @return bool\n     */\n    public function hasParameterOption($values)\n    {\n        $values = (array) $values;\n\n        foreach ($this->tokens as $token) {\n            foreach ($values as $value) {\n                if ($token === $value || 0 === strpos($token, $value . '=')) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * 获取原始选项的值\n     * @param string|array $values  需要检查的值\n     * @param mixed        $default 默认值\n     * @return mixed The option value\n     */\n    public function getParameterOption($values, $default = false)\n    {\n        $values = (array) $values;\n        $tokens = $this->tokens;\n\n        while (0 < count($tokens)) {\n            $token = array_shift($tokens);\n\n            foreach ($values as $value) {\n                if ($token === $value || 0 === strpos($token, $value . '=')) {\n                    if (false !== $pos = strpos($token, '=')) {\n                        return substr($token, $pos + 1);\n                    }\n\n                    return array_shift($tokens);\n                }\n            }\n        }\n\n        return $default;\n    }\n\n    /**\n     * 验证输入\n     * @throws \\RuntimeException\n     */\n    public function validate()\n    {\n        if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) {\n            throw new \\RuntimeException('Not enough arguments.');\n        }\n    }\n\n    /**\n     * 检查输入是否是交互的\n     * @return bool\n     */\n    public function isInteractive()\n    {\n        return $this->interactive;\n    }\n\n    /**\n     * 设置输入的交互\n     * @param bool\n     */\n    public function setInteractive($interactive)\n    {\n        $this->interactive = (bool) $interactive;\n    }\n\n    /**\n     * 获取所有的参数\n     * @return Argument[]\n     */\n    public function getArguments()\n    {\n        return array_merge($this->definition->getArgumentDefaults(), $this->arguments);\n    }\n\n    /**\n     * 根据名称获取参数\n     * @param string $name 参数名\n     * @return mixed\n     * @throws \\InvalidArgumentException\n     */\n    public function getArgument($name)\n    {\n        if (!$this->definition->hasArgument($name)) {\n            throw new \\InvalidArgumentException(sprintf('The \"%s\" argument does not exist.', $name));\n        }\n\n        return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)\n            ->getDefault();\n    }\n\n    /**\n     * 设置参数的值\n     * @param string $name  参数名\n     * @param string $value 值\n     * @throws \\InvalidArgumentException\n     */\n    public function setArgument($name, $value)\n    {\n        if (!$this->definition->hasArgument($name)) {\n            throw new \\InvalidArgumentException(sprintf('The \"%s\" argument does not exist.', $name));\n        }\n\n        $this->arguments[$name] = $value;\n    }\n\n    /**\n     * 检查是否存在某个参数\n     * @param string|int $name 参数名或位置\n     * @return bool\n     */\n    public function hasArgument($name)\n    {\n        return $this->definition->hasArgument($name);\n    }\n\n    /**\n     * 获取所有的选项\n     * @return Option[]\n     */\n    public function getOptions()\n    {\n        return array_merge($this->definition->getOptionDefaults(), $this->options);\n    }\n\n    /**\n     * 获取选项值\n     * @param string $name 选项名称\n     * @return mixed\n     * @throws \\InvalidArgumentException\n     */\n    public function getOption($name)\n    {\n        if (!$this->definition->hasOption($name)) {\n            throw new \\InvalidArgumentException(sprintf('The \"%s\" option does not exist.', $name));\n        }\n\n        return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();\n    }\n\n    /**\n     * 设置选项值\n     * @param string      $name  选项名\n     * @param string|bool $value 值\n     * @throws \\InvalidArgumentException\n     */\n    public function setOption($name, $value)\n    {\n        if (!$this->definition->hasOption($name)) {\n            throw new \\InvalidArgumentException(sprintf('The \"%s\" option does not exist.', $name));\n        }\n\n        $this->options[$name] = $value;\n    }\n\n    /**\n     * 是否有某个选项\n     * @param string $name 选项名\n     * @return bool\n     */\n    public function hasOption($name)\n    {\n        return $this->definition->hasOption($name) && isset($this->options[$name]);\n    }\n\n    /**\n     * 转义指令\n     * @param string $token\n     * @return string\n     */\n    public function escapeToken($token)\n    {\n        return preg_match('{^[\\w-]+$}', $token) ? $token : escapeshellarg($token);\n    }\n\n    /**\n     * 返回传递给命令的参数的字符串\n     * @return string\n     */\n    public function __toString()\n    {\n        $tokens = array_map(function ($token) {\n            if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {\n                return $match[1] . $this->escapeToken($match[2]);\n            }\n\n            if ($token && '-' !== $token[0]) {\n                return $this->escapeToken($token);\n            }\n\n            return $token;\n        }, $this->tokens);\n\n        return implode(' ', $tokens);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/LICENSE",
    "content": "Copyright (c) 2004-2016 Fabien Potencier\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 furnished\nto 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\nTHE SOFTWARE."
  },
  {
    "path": "thinkphp/library/think/console/Output.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console;\n\nuse Exception;\nuse think\\console\\output\\Ask;\nuse think\\console\\output\\Descriptor;\nuse think\\console\\output\\driver\\Buffer;\nuse think\\console\\output\\driver\\Console;\nuse think\\console\\output\\driver\\Nothing;\nuse think\\console\\output\\Question;\nuse think\\console\\output\\question\\Choice;\nuse think\\console\\output\\question\\Confirmation;\n\n/**\n * Class Output\n * @package think\\console\n *\n * @see     \\think\\console\\output\\driver\\Console::setDecorated\n * @method void setDecorated($decorated)\n *\n * @see     \\think\\console\\output\\driver\\Buffer::fetch\n * @method string fetch()\n *\n * @method void info($message)\n * @method void error($message)\n * @method void comment($message)\n * @method void warning($message)\n * @method void highlight($message)\n * @method void question($message)\n */\nclass Output\n{\n    const VERBOSITY_QUIET        = 0;\n    const VERBOSITY_NORMAL       = 1;\n    const VERBOSITY_VERBOSE      = 2;\n    const VERBOSITY_VERY_VERBOSE = 3;\n    const VERBOSITY_DEBUG        = 4;\n\n    const OUTPUT_NORMAL = 0;\n    const OUTPUT_RAW    = 1;\n    const OUTPUT_PLAIN  = 2;\n\n    private $verbosity = self::VERBOSITY_NORMAL;\n\n    /** @var Buffer|Console|Nothing */\n    private $handle = null;\n\n    protected $styles = [\n        'info',\n        'error',\n        'comment',\n        'question',\n        'highlight',\n        'warning'\n    ];\n\n    public function __construct($driver = 'console')\n    {\n        $class = '\\\\think\\\\console\\\\output\\\\driver\\\\' . ucwords($driver);\n\n        $this->handle = new $class($this);\n    }\n\n    public function ask(Input $input, $question, $default = null, $validator = null)\n    {\n        $question = new Question($question, $default);\n        $question->setValidator($validator);\n\n        return $this->askQuestion($input, $question);\n    }\n\n    public function askHidden(Input $input, $question, $validator = null)\n    {\n        $question = new Question($question);\n\n        $question->setHidden(true);\n        $question->setValidator($validator);\n\n        return $this->askQuestion($input, $question);\n    }\n\n    public function confirm(Input $input, $question, $default = true)\n    {\n        return $this->askQuestion($input, new Confirmation($question, $default));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function choice(Input $input, $question, array $choices, $default = null)\n    {\n        if (null !== $default) {\n            $values  = array_flip($choices);\n            $default = $values[$default];\n        }\n\n        return $this->askQuestion($input, new Choice($question, $choices, $default));\n    }\n\n    protected function askQuestion(Input $input, Question $question)\n    {\n        $ask    = new Ask($input, $this, $question);\n        $answer = $ask->run();\n\n        if ($input->isInteractive()) {\n            $this->newLine();\n        }\n\n        return $answer;\n    }\n\n    protected function block($style, $message)\n    {\n        $this->writeln(\"<{$style}>{$message}</$style>\");\n    }\n\n    /**\n     * 输出空行\n     * @param int $count\n     */\n    public function newLine($count = 1)\n    {\n        $this->write(str_repeat(PHP_EOL, $count));\n    }\n\n    /**\n     * 输出信息并换行\n     * @param string $messages\n     * @param int    $type\n     */\n    public function writeln($messages, $type = self::OUTPUT_NORMAL)\n    {\n        $this->write($messages, true, $type);\n    }\n\n    /**\n     * 输出信息\n     * @param string $messages\n     * @param bool   $newline\n     * @param int    $type\n     */\n    public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)\n    {\n        $this->handle->write($messages, $newline, $type);\n    }\n\n    public function renderException(\\Exception $e)\n    {\n        $this->handle->renderException($e);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setVerbosity($level)\n    {\n        $this->verbosity = (int) $level;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getVerbosity()\n    {\n        return $this->verbosity;\n    }\n\n    public function isQuiet()\n    {\n        return self::VERBOSITY_QUIET === $this->verbosity;\n    }\n\n    public function isVerbose()\n    {\n        return self::VERBOSITY_VERBOSE <= $this->verbosity;\n    }\n\n    public function isVeryVerbose()\n    {\n        return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;\n    }\n\n    public function isDebug()\n    {\n        return self::VERBOSITY_DEBUG <= $this->verbosity;\n    }\n\n    public function describe($object, array $options = [])\n    {\n        $descriptor = new Descriptor();\n        $options    = array_merge([\n            'raw_text' => false,\n        ], $options);\n\n        $descriptor->describe($this, $object, $options);\n    }\n\n    public function __call($method, $args)\n    {\n        if (in_array($method, $this->styles)) {\n            array_unshift($args, $method);\n            return call_user_func_array([$this, 'block'], $args);\n        }\n\n        if ($this->handle && method_exists($this->handle, $method)) {\n            return call_user_func_array([$this->handle, $method], $args);\n        } else {\n            throw new Exception('method not exists:' . __CLASS__ . '->' . $method);\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/bin/README.md",
    "content": "console 工具使用 hiddeninput.exe 在 windows 上隐藏密码输入，该二进制文件由第三方提供，相关源码和其他细节可以在 [Hidden Input](https://github.com/Seldaek/hidden-input) 找到。\n"
  },
  {
    "path": "thinkphp/library/think/console/command/Build.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\command;\n\nuse think\\console\\Command;\nuse think\\console\\Input;\nuse think\\console\\input\\Option;\nuse think\\console\\Output;\n\nclass Build extends Command\n{\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function configure()\n    {\n        $this->setName('build')\n            ->setDefinition([\n                new Option('config', null, Option::VALUE_OPTIONAL, \"build.php path\"),\n                new Option('module', null, Option::VALUE_OPTIONAL, \"module name\"),\n            ])\n            ->setDescription('Build Application Dirs');\n    }\n\n    protected function execute(Input $input, Output $output)\n    {\n        if ($input->hasOption('module')) {\n            \\think\\Build::module($input->getOption('module'));\n            $output->writeln(\"Successed\");\n            return;\n        }\n\n        if ($input->hasOption('config')) {\n            $build = include $input->getOption('config');\n        } else {\n            $build = include APP_PATH . 'build.php';\n        }\n        if (empty($build)) {\n            $output->writeln(\"Build Config Is Empty\");\n            return;\n        }\n        \\think\\Build::run($build);\n        $output->writeln(\"Successed\");\n\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/Clear.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace think\\console\\command;\n\nuse think\\console\\Command;\nuse think\\console\\Input;\nuse think\\console\\input\\Option;\nuse think\\console\\Output;\n\nclass Clear extends Command\n{\n    protected function configure()\n    {\n        // 指令配置\n        $this\n            ->setName('clear')\n            ->addOption('path', 'd', Option::VALUE_OPTIONAL, 'path to clear', null)\n            ->setDescription('Clear runtime file');\n    }\n\n    protected function execute(Input $input, Output $output)\n    {\n        $path = $input->getOption('path') ?: RUNTIME_PATH;\n\n        if (is_dir($path)) {\n            $this->clearPath($path);\n        }\n\n        $output->writeln(\"<info>Clear Successed</info>\");\n    }\n\n    protected function clearPath($path)\n    {\n        $path  = realpath($path) . DS;\n        $files = scandir($path);\n        if ($files) {\n            foreach ($files as $file) {\n                if ('.' != $file && '..' != $file && is_dir($path . $file)) {\n                    $this->clearPath($path . $file);\n                } elseif ('.gitignore' != $file && is_file($path . $file)) {\n                    unlink($path . $file);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/Help.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\command;\n\nuse think\\console\\Command;\nuse think\\console\\Input;\nuse think\\console\\input\\Argument as InputArgument;\nuse think\\console\\input\\Option as InputOption;\nuse think\\console\\Output;\n\nclass Help extends Command\n{\n\n    private $command;\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function configure()\n    {\n        $this->ignoreValidationErrors();\n\n        $this->setName('help')->setDefinition([\n            new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),\n            new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),\n        ])->setDescription('Displays help for a command')->setHelp(<<<EOF\nThe <info>%command.name%</info> command displays help for a given command:\n\n  <info>php %command.full_name% list</info>\n\nTo display the list of available commands, please use the <info>list</info> command.\nEOF\n        );\n    }\n\n    /**\n     * Sets the command.\n     * @param Command $command The command to set\n     */\n    public function setCommand(Command $command)\n    {\n        $this->command = $command;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function execute(Input $input, Output $output)\n    {\n        if (null === $this->command) {\n            $this->command = $this->getConsole()->find($input->getArgument('command_name'));\n        }\n\n        $output->describe($this->command, [\n            'raw_text' => $input->getOption('raw'),\n        ]);\n\n        $this->command = null;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/Lists.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\command;\n\nuse think\\console\\Command;\nuse think\\console\\Input;\nuse think\\console\\Output;\nuse think\\console\\input\\Argument as InputArgument;\nuse think\\console\\input\\Option as InputOption;\nuse think\\console\\input\\Definition as InputDefinition;\n\nclass Lists extends Command\n{\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function configure()\n    {\n        $this->setName('list')->setDefinition($this->createDefinition())->setDescription('Lists commands')->setHelp(<<<EOF\nThe <info>%command.name%</info> command lists all commands:\n\n  <info>php %command.full_name%</info>\n\nYou can also display the commands for a specific namespace:\n\n  <info>php %command.full_name% test</info>\n\nIt's also possible to get raw list of commands (useful for embedding command runner):\n\n  <info>php %command.full_name% --raw</info>\nEOF\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getNativeDefinition()\n    {\n        return $this->createDefinition();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function execute(Input $input, Output $output)\n    {\n        $output->describe($this->getConsole(), [\n            'raw_text'  => $input->getOption('raw'),\n            'namespace' => $input->getArgument('namespace'),\n        ]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    private function createDefinition()\n    {\n        return new InputDefinition([\n            new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),\n            new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list')\n        ]);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/Make.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 刘志淳 <chun@engineer.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\command;\n\nuse think\\App;\nuse think\\Config;\nuse think\\console\\Command;\nuse think\\console\\Input;\nuse think\\console\\input\\Argument;\nuse think\\console\\Output;\n\nabstract class Make extends Command\n{\n\n    protected $type;\n\n    abstract protected function getStub();\n\n    protected function configure()\n    {\n        $this->addArgument('name', Argument::REQUIRED, \"The name of the class\");\n    }\n\n    protected function execute(Input $input, Output $output)\n    {\n\n        $name = trim($input->getArgument('name'));\n\n        $classname = $this->getClassName($name);\n\n        $pathname = $this->getPathName($classname);\n\n        if (is_file($pathname)) {\n            $output->writeln('<error>' . $this->type . ' already exists!</error>');\n            return false;\n        }\n\n        if (!is_dir(dirname($pathname))) {\n            mkdir(strtolower(dirname($pathname)), 0755, true);\n        }\n\n        file_put_contents($pathname, $this->buildClass($classname));\n\n        $output->writeln('<info>' . $this->type . ' created successfully.</info>');\n\n    }\n\n    protected function buildClass($name)\n    {\n        $stub = file_get_contents($this->getStub());\n\n        $namespace = trim(implode('\\\\', array_slice(explode('\\\\', $name), 0, -1)), '\\\\');\n\n        $class = str_replace($namespace . '\\\\', '', $name);\n\n        return str_replace(['{%className%}', '{%namespace%}', '{%app_namespace%}'], [\n            $class,\n            $namespace,\n            App::$namespace,\n        ], $stub);\n\n    }\n\n    protected function getPathName($name)\n    {\n        $name = str_replace(App::$namespace . '\\\\', '', $name);\n\n        return APP_PATH . str_replace('\\\\', '/', $name) . '.php';\n    }\n\n    protected function getClassName($name)\n    {\n        $appNamespace = App::$namespace;\n\n        if (strpos($name, $appNamespace . '\\\\') === 0) {\n            return $name;\n        }\n\n        if (Config::get('app_multi_module')) {\n            if (strpos($name, '/')) {\n                list($module, $name) = explode('/', $name, 2);\n            } else {\n                $module = 'common';\n            }\n        } else {\n            $module = null;\n        }\n\n        if (strpos($name, '/') !== false) {\n            $name = str_replace('/', '\\\\', $name);\n        }\n\n        return $this->getNamespace($appNamespace, $module) . '\\\\' . $name;\n    }\n\n    protected function getNamespace($appNamespace, $module)\n    {\n        return $module ? ($appNamespace . '\\\\' . $module) : $appNamespace;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/make/Controller.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 刘志淳 <chun@engineer.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\command\\make;\n\nuse think\\Config;\nuse think\\console\\command\\Make;\nuse think\\console\\input\\Option;\n\nclass Controller extends Make\n{\n\n    protected $type = \"Controller\";\n\n    protected function configure()\n    {\n        parent::configure();\n        $this->setName('make:controller')\n            ->addOption('plain', null, Option::VALUE_NONE, 'Generate an empty controller class.')\n            ->setDescription('Create a new resource controller class');\n    }\n\n    protected function getStub()\n    {\n        if ($this->input->getOption('plain')) {\n            return __DIR__ . '/stubs/controller.plain.stub';\n        }\n\n        return __DIR__ . '/stubs/controller.stub';\n    }\n\n    protected function getClassName($name)\n    {\n        return parent::getClassName($name) . (Config::get('controller_suffix') ? ucfirst(Config::get('url_controller_layer')) : '');\n    }\n\n    protected function getNamespace($appNamespace, $module)\n    {\n        return parent::getNamespace($appNamespace, $module) . '\\controller';\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/make/Model.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 刘志淳 <chun@engineer.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\command\\make;\n\nuse think\\console\\command\\Make;\n\nclass Model extends Make\n{\n    protected $type = \"Model\";\n\n    protected function configure()\n    {\n        parent::configure();\n        $this->setName('make:model')\n            ->setDescription('Create a new model class');\n    }\n\n    protected function getStub()\n    {\n        return __DIR__ . '/stubs/model.stub';\n    }\n\n    protected function getNamespace($appNamespace, $module)\n    {\n        return parent::getNamespace($appNamespace, $module) . '\\model';\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/make/stubs/controller.plain.stub",
    "content": "<?php\n\nnamespace {%namespace%};\n\nuse think\\Controller;\n\nclass {%className%} extends Controller\n{\n    //\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/make/stubs/controller.stub",
    "content": "<?php\n\nnamespace {%namespace%};\n\nuse think\\Controller;\nuse think\\Request;\n\nclass {%className%} extends Controller\n{\n    /**\n     * 显示资源列表\n     *\n     * @return \\think\\Response\n     */\n    public function index()\n    {\n        //\n    }\n\n    /**\n     * 显示创建资源表单页.\n     *\n     * @return \\think\\Response\n     */\n    public function create()\n    {\n        //\n    }\n\n    /**\n     * 保存新建的资源\n     *\n     * @param  \\think\\Request  $request\n     * @return \\think\\Response\n     */\n    public function save(Request $request)\n    {\n        //\n    }\n\n    /**\n     * 显示指定的资源\n     *\n     * @param  int  $id\n     * @return \\think\\Response\n     */\n    public function read($id)\n    {\n        //\n    }\n\n    /**\n     * 显示编辑资源表单页.\n     *\n     * @param  int  $id\n     * @return \\think\\Response\n     */\n    public function edit($id)\n    {\n        //\n    }\n\n    /**\n     * 保存更新的资源\n     *\n     * @param  \\think\\Request  $request\n     * @param  int  $id\n     * @return \\think\\Response\n     */\n    public function update(Request $request, $id)\n    {\n        //\n    }\n\n    /**\n     * 删除指定资源\n     *\n     * @param  int  $id\n     * @return \\think\\Response\n     */\n    public function delete($id)\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/make/stubs/model.stub",
    "content": "<?php\n\nnamespace {%namespace%};\n\nuse think\\Model;\n\nclass {%className%} extends Model\n{\n    //\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/optimize/Autoload.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\nnamespace think\\console\\command\\optimize;\n\nuse think\\App;\nuse think\\Config;\nuse think\\console\\Command;\nuse think\\console\\Input;\nuse think\\console\\Output;\n\nclass Autoload extends Command\n{\n\n    protected function configure()\n    {\n        $this->setName('optimize:autoload')\n            ->setDescription('Optimizes PSR0 and PSR4 packages to be loaded with classmaps too, good for production.');\n    }\n\n    protected function execute(Input $input, Output $output)\n    {\n\n        $classmapFile = <<<EOF\n<?php\n/**\n * 类库映射\n */\n\nreturn [\n\nEOF;\n\n        $namespacesToScan = [\n            App::$namespace . '\\\\' => realpath(rtrim(APP_PATH)),\n            'think\\\\'              => LIB_PATH . 'think',\n            'behavior\\\\'           => LIB_PATH . 'behavior',\n            'traits\\\\'             => LIB_PATH . 'traits',\n            ''                     => realpath(rtrim(EXTEND_PATH)),\n        ];\n\n        $root_namespace = Config::get('root_namespace');\n        foreach ($root_namespace as $namespace => $dir) {\n            $namespacesToScan[$namespace . '\\\\'] = realpath($dir);\n        }\n\n        krsort($namespacesToScan);\n        $classMap = [];\n        foreach ($namespacesToScan as $namespace => $dir) {\n\n            if (!is_dir($dir)) {\n                continue;\n            }\n\n            $namespaceFilter = $namespace === '' ? null : $namespace;\n            $classMap        = $this->addClassMapCode($dir, $namespaceFilter, $classMap);\n        }\n\n        ksort($classMap);\n        foreach ($classMap as $class => $code) {\n            $classmapFile .= '    ' . var_export($class, true) . ' => ' . $code;\n        }\n        $classmapFile .= \"];\\n\";\n\n        if (!is_dir(RUNTIME_PATH)) {\n            @mkdir(RUNTIME_PATH, 0755, true);\n        }\n\n        file_put_contents(RUNTIME_PATH . 'classmap' . EXT, $classmapFile);\n\n        $output->writeln('<info>Succeed!</info>');\n    }\n\n    protected function addClassMapCode($dir, $namespace, $classMap)\n    {\n        foreach ($this->createMap($dir, $namespace) as $class => $path) {\n\n            $pathCode = $this->getPathCode($path) . \",\\n\";\n\n            if (!isset($classMap[$class])) {\n                $classMap[$class] = $pathCode;\n            } elseif ($classMap[$class] !== $pathCode && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($classMap[$class] . ' ' . $path, '\\\\', '/'))) {\n                $this->output->writeln(\n                    '<warning>Warning: Ambiguous class resolution, \"' . $class . '\"' .\n                    ' was found in both \"' . str_replace([\"',\\n\"], [\n                        '',\n                    ], $classMap[$class]) . '\" and \"' . $path . '\", the first will be used.</warning>'\n                );\n            }\n        }\n        return $classMap;\n    }\n\n    protected function getPathCode($path)\n    {\n\n        $baseDir    = '';\n        $libPath    = $this->normalizePath(realpath(LIB_PATH));\n        $appPath    = $this->normalizePath(realpath(APP_PATH));\n        $extendPath = $this->normalizePath(realpath(EXTEND_PATH));\n        $rootPath   = $this->normalizePath(realpath(ROOT_PATH));\n        $path       = $this->normalizePath($path);\n\n        if ($libPath !== null && strpos($path, $libPath . '/') === 0) {\n            $path    = substr($path, strlen(LIB_PATH));\n            $baseDir = 'LIB_PATH';\n        } elseif ($appPath !== null && strpos($path, $appPath . '/') === 0) {\n            $path    = substr($path, strlen($appPath) + 1);\n            $baseDir = 'APP_PATH';\n        } elseif ($extendPath !== null && strpos($path, $extendPath . '/') === 0) {\n            $path    = substr($path, strlen($extendPath) + 1);\n            $baseDir = 'EXTEND_PATH';\n        } elseif ($rootPath !== null && strpos($path, $rootPath . '/') === 0) {\n            $path    = substr($path, strlen($rootPath) + 1);\n            $baseDir = 'ROOT_PATH';\n        }\n\n        if ($path !== false) {\n            $baseDir .= \" . \";\n        }\n\n        return $baseDir . (($path !== false) ? var_export($path, true) : \"\");\n    }\n\n    protected function normalizePath($path)\n    {\n        if ($path === false) {\n            return;\n        }\n        $parts    = [];\n        $path     = strtr($path, '\\\\', '/');\n        $prefix   = '';\n        $absolute = false;\n\n        if (preg_match('{^([0-9a-z]+:(?://(?:[a-z]:)?)?)}i', $path, $match)) {\n            $prefix = $match[1];\n            $path   = substr($path, strlen($prefix));\n        }\n\n        if (substr($path, 0, 1) === '/') {\n            $absolute = true;\n            $path     = substr($path, 1);\n        }\n\n        $up = false;\n        foreach (explode('/', $path) as $chunk) {\n            if ('..' === $chunk && ($absolute || $up)) {\n                array_pop($parts);\n                $up = !(empty($parts) || '..' === end($parts));\n            } elseif ('.' !== $chunk && '' !== $chunk) {\n                $parts[] = $chunk;\n                $up      = '..' !== $chunk;\n            }\n        }\n\n        return $prefix . ($absolute ? '/' : '') . implode('/', $parts);\n    }\n\n    protected function createMap($path, $namespace = null)\n    {\n        if (is_string($path)) {\n            if (is_file($path)) {\n                $path = [new \\SplFileInfo($path)];\n            } elseif (is_dir($path)) {\n\n                $objects = new \\RecursiveIteratorIterator(new \\RecursiveDirectoryIterator($path), \\RecursiveIteratorIterator::SELF_FIRST);\n\n                $path = [];\n\n                /** @var \\SplFileInfo $object */\n                foreach ($objects as $object) {\n                    if ($object->isFile() && $object->getExtension() == 'php') {\n                        $path[] = $object;\n                    }\n                }\n            } else {\n                throw new \\RuntimeException(\n                    'Could not scan for classes inside \"' . $path .\n                    '\" which does not appear to be a file nor a folder'\n                );\n            }\n        }\n\n        $map = [];\n\n        /** @var \\SplFileInfo $file */\n        foreach ($path as $file) {\n            $filePath = $file->getRealPath();\n\n            if (pathinfo($filePath, PATHINFO_EXTENSION) != 'php') {\n                continue;\n            }\n\n            $classes = $this->findClasses($filePath);\n\n            foreach ($classes as $class) {\n                if (null !== $namespace && 0 !== strpos($class, $namespace)) {\n                    continue;\n                }\n\n                if (!isset($map[$class])) {\n                    $map[$class] = $filePath;\n                } elseif ($map[$class] !== $filePath && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($map[$class] . ' ' . $filePath, '\\\\', '/'))) {\n                    $this->output->writeln(\n                        '<warning>Warning: Ambiguous class resolution, \"' . $class . '\"' .\n                        ' was found in both \"' . $map[$class] . '\" and \"' . $filePath . '\", the first will be used.</warning>'\n                    );\n                }\n            }\n        }\n\n        return $map;\n    }\n\n    protected function findClasses($path)\n    {\n        $extraTypes = '|trait';\n\n        $contents = @php_strip_whitespace($path);\n        if (!$contents) {\n            if (!file_exists($path)) {\n                $message = 'File at \"%s\" does not exist, check your classmap definitions';\n            } elseif (!is_readable($path)) {\n                $message = 'File at \"%s\" is not readable, check its permissions';\n            } elseif ('' === trim(file_get_contents($path))) {\n                return [];\n            } else {\n                $message = 'File at \"%s\" could not be parsed as PHP, it may be binary or corrupted';\n            }\n            $error = error_get_last();\n            if (isset($error['message'])) {\n                $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];\n            }\n            throw new \\RuntimeException(sprintf($message, $path));\n        }\n\n        if (!preg_match('{\\b(?:class|interface' . $extraTypes . ')\\s}i', $contents)) {\n            return [];\n        }\n\n        // strip heredocs/nowdocs\n        $contents = preg_replace('{<<<\\s*(\\'?)(\\w+)\\\\1(?:\\r\\n|\\n|\\r)(?:.*?)(?:\\r\\n|\\n|\\r)\\\\2(?=\\r\\n|\\n|\\r|;)}s', 'null', $contents);\n        // strip strings\n        $contents = preg_replace('{\"[^\"\\\\\\\\]*+(\\\\\\\\.[^\"\\\\\\\\]*+)*+\"|\\'[^\\'\\\\\\\\]*+(\\\\\\\\.[^\\'\\\\\\\\]*+)*+\\'}s', 'null', $contents);\n        // strip leading non-php code if needed\n        if (substr($contents, 0, 2) !== '<?') {\n            $contents = preg_replace('{^.+?<\\?}s', '<?', $contents, 1, $replacements);\n            if ($replacements === 0) {\n                return [];\n            }\n        }\n        // strip non-php blocks in the file\n        $contents = preg_replace('{\\?>.+<\\?}s', '?><?', $contents);\n        // strip trailing non-php code if needed\n        $pos = strrpos($contents, '?>');\n        if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {\n            $contents = substr($contents, 0, $pos);\n        }\n\n        preg_match_all('{\n            (?:\n                 \\b(?<![\\$:>])(?P<type>class|interface' . $extraTypes . ') \\s++ (?P<name>[a-zA-Z_\\x7f-\\xff:][a-zA-Z0-9_\\x7f-\\xff:\\-]*+)\n               | \\b(?<![\\$:>])(?P<ns>namespace) (?P<nsname>\\s++[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*+(?:\\s*+\\\\\\\\\\s*+[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*+)*+)? \\s*+ [\\{;]\n            )\n        }ix', $contents, $matches);\n\n        $classes   = [];\n        $namespace = '';\n\n        for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {\n            if (!empty($matches['ns'][$i])) {\n                $namespace = str_replace([' ', \"\\t\", \"\\r\", \"\\n\"], '', $matches['nsname'][$i]) . '\\\\';\n            } else {\n                $name = $matches['name'][$i];\n                if ($name[0] === ':') {\n                    $name = 'xhp' . substr(str_replace(['-', ':'], ['_', '__'], $name), 1);\n                } elseif ($matches['type'][$i] === 'enum') {\n                    $name = rtrim($name, ':');\n                }\n                $classes[] = ltrim($namespace . $name, '\\\\');\n            }\n        }\n\n        return $classes;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/optimize/Config.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\nnamespace think\\console\\command\\optimize;\n\nuse think\\Config as ThinkConfig;\nuse think\\console\\Command;\nuse think\\console\\Input;\nuse think\\console\\input\\Argument;\nuse think\\console\\Output;\n\nclass Config extends Command\n{\n    /** @var  Output */\n    protected $output;\n\n    protected function configure()\n    {\n        $this->setName('optimize:config')\n            ->addArgument('module', Argument::OPTIONAL, 'Build module config cache .')\n            ->setDescription('Build config and common file cache.');\n    }\n\n    protected function execute(Input $input, Output $output)\n    {\n        if ($input->hasArgument('module')) {\n            $module = $input->getArgument('module') . DS;\n        } else {\n            $module = '';\n        }\n\n        $content = '<?php ' . PHP_EOL . $this->buildCacheContent($module);\n\n        if (!is_dir(RUNTIME_PATH . $module)) {\n            @mkdir(RUNTIME_PATH . $module, 0755, true);\n        }\n\n        file_put_contents(RUNTIME_PATH . $module . 'init' . EXT, $content);\n\n        $output->writeln('<info>Succeed!</info>');\n    }\n\n    protected function buildCacheContent($module)\n    {\n        $content = '';\n        $path    = realpath(APP_PATH . $module) . DS;\n\n        if ($module) {\n            // 加载模块配置\n            $config = ThinkConfig::load(CONF_PATH . $module . 'config' . CONF_EXT);\n\n            // 读取数据库配置文件\n            $filename = CONF_PATH . $module . 'database' . CONF_EXT;\n            ThinkConfig::load($filename, 'database');\n\n            // 加载应用状态配置\n            if ($config['app_status']) {\n                $config = ThinkConfig::load(CONF_PATH . $module . $config['app_status'] . CONF_EXT);\n            }\n            // 读取扩展配置文件\n            if (is_dir(CONF_PATH . $module . 'extra')) {\n                $dir   = CONF_PATH . $module . 'extra';\n                $files = scandir($dir);\n                foreach ($files as $file) {\n                    if (strpos($file, CONF_EXT)) {\n                        $filename = $dir . DS . $file;\n                        ThinkConfig::load($filename, pathinfo($file, PATHINFO_FILENAME));\n                    }\n                }\n            }\n        }\n\n        // 加载行为扩展文件\n        if (is_file(CONF_PATH . $module . 'tags' . EXT)) {\n            $content .= '\\think\\Hook::import(' . (var_export(include CONF_PATH . $module . 'tags' . EXT, true)) . ');' . PHP_EOL;\n        }\n\n        // 加载公共文件\n        if (is_file($path . 'common' . EXT)) {\n            $content .= substr(php_strip_whitespace($path . 'common' . EXT), 5) . PHP_EOL;\n        }\n\n        $content .= '\\think\\Config::set(' . var_export(ThinkConfig::get(), true) . ');';\n        return $content;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/optimize/Route.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace think\\console\\command\\optimize;\n\nuse think\\console\\Command;\nuse think\\console\\Input;\nuse think\\console\\Output;\n\nclass Route extends Command\n{\n    /** @var  Output */\n    protected $output;\n\n    protected function configure()\n    {\n        $this->setName('optimize:route')\n            ->setDescription('Build route cache.');\n    }\n\n    protected function execute(Input $input, Output $output)\n    {\n        file_put_contents(RUNTIME_PATH . 'route.php', $this->buildRouteCache());\n        $output->writeln('<info>Succeed!</info>');\n    }\n\n    protected function buildRouteCache()\n    {\n        $files = \\think\\Config::get('route_config_file');\n        foreach ($files as $file) {\n            if (is_file(CONF_PATH . $file . CONF_EXT)) {\n                $config = include CONF_PATH . $file . CONF_EXT;\n                if (is_array($config)) {\n                    \\think\\Route::import($config);\n                }\n            }\n        }\n        $rules = \\think\\Route::rules(true);\n        array_walk_recursive($rules, [$this, 'buildClosure']);\n        $content = '<?php ' . PHP_EOL . 'return ';\n        $content .= var_export($rules, true) . ';';\n        $content = str_replace(['\\'[__start__', '__end__]\\''], '', stripcslashes($content));\n        return $content;\n    }\n\n    protected function buildClosure(&$value)\n    {\n        if ($value instanceof \\Closure) {\n            $reflection = new \\ReflectionFunction($value);\n            $startLine  = $reflection->getStartLine();\n            $endLine    = $reflection->getEndLine();\n            $file       = $reflection->getFileName();\n            $item       = file($file);\n            $content    = '';\n            for ($i = $startLine - 1; $i <= $endLine - 1; $i++) {\n                $content .= $item[$i];\n            }\n            $start = strpos($content, 'function');\n            $end   = strrpos($content, '}');\n            $value = '[__start__' . substr($content, $start, $end - $start + 1) . '__end__]';\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/command/optimize/Schema.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\nnamespace think\\console\\command\\optimize;\n\nuse think\\App;\nuse think\\console\\Command;\nuse think\\console\\Input;\nuse think\\console\\input\\Option;\nuse think\\console\\Output;\nuse think\\Db;\n\nclass Schema extends Command\n{\n    /** @var  Output */\n    protected $output;\n\n    protected function configure()\n    {\n        $this->setName('optimize:schema')\n            ->addOption('config', null, Option::VALUE_REQUIRED, 'db config .')\n            ->addOption('db', null, Option::VALUE_REQUIRED, 'db name .')\n            ->addOption('table', null, Option::VALUE_REQUIRED, 'table name .')\n            ->addOption('module', null, Option::VALUE_REQUIRED, 'module name .')\n            ->setDescription('Build database schema cache.');\n    }\n\n    protected function execute(Input $input, Output $output)\n    {\n        if (!is_dir(RUNTIME_PATH . 'schema')) {\n            @mkdir(RUNTIME_PATH . 'schema', 0755, true);\n        }\n        $config = [];\n        if ($input->hasOption('config')) {\n            $config = $input->getOption('config');\n        }\n        if ($input->hasOption('module')) {\n            $module = $input->getOption('module');\n            // 读取模型\n            $list = scandir(APP_PATH . $module . DS . 'model');\n            $app  = App::$namespace;\n            foreach ($list as $file) {\n                if (0 === strpos($file, '.')) {\n                    continue;\n                }\n                $class = '\\\\' . $app . '\\\\' . $module . '\\\\model\\\\' . pathinfo($file, PATHINFO_FILENAME);\n                $this->buildModelSchema($class);\n            }\n            $output->writeln('<info>Succeed!</info>');\n            return;\n        } elseif ($input->hasOption('table')) {\n            $table = $input->getOption('table');\n            if (!strpos($table, '.')) {\n                $dbName = Db::connect($config)->getConfig('database');\n            }\n            $tables[] = $table;\n        } elseif ($input->hasOption('db')) {\n            $dbName = $input->getOption('db');\n            $tables = Db::connect($config)->getTables($dbName);\n        } elseif (!\\think\\Config::get('app_multi_module')) {\n            $app  = App::$namespace;\n            $list = scandir(APP_PATH . 'model');\n            foreach ($list as $file) {\n                if (0 === strpos($file, '.')) {\n                    continue;\n                }\n                $class = '\\\\' . $app . '\\\\model\\\\' . pathinfo($file, PATHINFO_FILENAME);\n                $this->buildModelSchema($class);\n            }\n            $output->writeln('<info>Succeed!</info>');\n            return;\n        } else {\n            $tables = Db::connect($config)->getTables();\n        }\n\n        $db = isset($dbName) ? $dbName . '.' : '';\n        $this->buildDataBaseSchema($tables, $db, $config);\n\n        $output->writeln('<info>Succeed!</info>');\n    }\n\n    protected function buildModelSchema($class)\n    {\n        $reflect = new \\ReflectionClass($class);\n        if (!$reflect->isAbstract() && $reflect->isSubclassOf('\\think\\Model')) {\n            $table   = $class::getTable();\n            $dbName  = $class::getConfig('database');\n            $content = '<?php ' . PHP_EOL . 'return ';\n            $info    = $class::getConnection()->getFields($table);\n            $content .= var_export($info, true) . ';';\n            file_put_contents(RUNTIME_PATH . 'schema' . DS . $dbName . '.' . $table . EXT, $content);\n        }\n    }\n\n    protected function buildDataBaseSchema($tables, $db, $config)\n    {\n        if ('' == $db) {\n            $dbName = Db::connect($config)->getConfig('database') . '.';\n        } else {\n            $dbName = $db;\n        }\n        foreach ($tables as $table) {\n            $content = '<?php ' . PHP_EOL . 'return ';\n            $info    = Db::connect($config)->getFields($db . $table);\n            $content .= var_export($info, true) . ';';\n            file_put_contents(RUNTIME_PATH . 'schema' . DS . $dbName . $table . EXT, $content);\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/input/Argument.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\input;\n\nclass Argument\n{\n\n    const REQUIRED = 1;\n    const OPTIONAL = 2;\n    const IS_ARRAY = 4;\n\n    private $name;\n    private $mode;\n    private $default;\n    private $description;\n\n    /**\n     * 构造方法\n     * @param string $name        参数名\n     * @param int    $mode        参数类型: self::REQUIRED 或者 self::OPTIONAL\n     * @param string $description 描述\n     * @param mixed  $default     默认值 (仅 self::OPTIONAL 类型有效)\n     * @throws \\InvalidArgumentException\n     */\n    public function __construct($name, $mode = null, $description = '', $default = null)\n    {\n        if (null === $mode) {\n            $mode = self::OPTIONAL;\n        } elseif (!is_int($mode) || $mode > 7 || $mode < 1) {\n            throw new \\InvalidArgumentException(sprintf('Argument mode \"%s\" is not valid.', $mode));\n        }\n\n        $this->name        = $name;\n        $this->mode        = $mode;\n        $this->description = $description;\n\n        $this->setDefault($default);\n    }\n\n    /**\n     * 获取参数名\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * 是否必须\n     * @return bool\n     */\n    public function isRequired()\n    {\n        return self::REQUIRED === (self::REQUIRED & $this->mode);\n    }\n\n    /**\n     * 该参数是否接受数组\n     * @return bool\n     */\n    public function isArray()\n    {\n        return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);\n    }\n\n    /**\n     * 设置默认值\n     * @param mixed $default 默认值\n     * @throws \\LogicException\n     */\n    public function setDefault($default = null)\n    {\n        if (self::REQUIRED === $this->mode && null !== $default) {\n            throw new \\LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');\n        }\n\n        if ($this->isArray()) {\n            if (null === $default) {\n                $default = [];\n            } elseif (!is_array($default)) {\n                throw new \\LogicException('A default value for an array argument must be an array.');\n            }\n        }\n\n        $this->default = $default;\n    }\n\n    /**\n     * 获取默认值\n     * @return mixed\n     */\n    public function getDefault()\n    {\n        return $this->default;\n    }\n\n    /**\n     * 获取描述\n     * @return string\n     */\n    public function getDescription()\n    {\n        return $this->description;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/input/Definition.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\input;\n\nclass Definition\n{\n\n    /**\n     * @var Argument[]\n     */\n    private $arguments;\n\n    private $requiredCount;\n    private $hasAnArrayArgument = false;\n    private $hasOptional;\n\n    /**\n     * @var Option[]\n     */\n    private $options;\n    private $shortcuts;\n\n    /**\n     * 构造方法\n     * @param array $definition\n     * @api\n     */\n    public function __construct(array $definition = [])\n    {\n        $this->setDefinition($definition);\n    }\n\n    /**\n     * 设置指令的定义\n     * @param array $definition 定义的数组\n     */\n    public function setDefinition(array $definition)\n    {\n        $arguments = [];\n        $options   = [];\n        foreach ($definition as $item) {\n            if ($item instanceof Option) {\n                $options[] = $item;\n            } else {\n                $arguments[] = $item;\n            }\n        }\n\n        $this->setArguments($arguments);\n        $this->setOptions($options);\n    }\n\n    /**\n     * 设置参数\n     * @param Argument[] $arguments 参数数组\n     */\n    public function setArguments($arguments = [])\n    {\n        $this->arguments          = [];\n        $this->requiredCount      = 0;\n        $this->hasOptional        = false;\n        $this->hasAnArrayArgument = false;\n        $this->addArguments($arguments);\n    }\n\n    /**\n     * 添加参数\n     * @param Argument[] $arguments 参数数组\n     * @api\n     */\n    public function addArguments($arguments = [])\n    {\n        if (null !== $arguments) {\n            foreach ($arguments as $argument) {\n                $this->addArgument($argument);\n            }\n        }\n    }\n\n    /**\n     * 添加一个参数\n     * @param Argument $argument 参数\n     * @throws \\LogicException\n     */\n    public function addArgument(Argument $argument)\n    {\n        if (isset($this->arguments[$argument->getName()])) {\n            throw new \\LogicException(sprintf('An argument with name \"%s\" already exists.', $argument->getName()));\n        }\n\n        if ($this->hasAnArrayArgument) {\n            throw new \\LogicException('Cannot add an argument after an array argument.');\n        }\n\n        if ($argument->isRequired() && $this->hasOptional) {\n            throw new \\LogicException('Cannot add a required argument after an optional one.');\n        }\n\n        if ($argument->isArray()) {\n            $this->hasAnArrayArgument = true;\n        }\n\n        if ($argument->isRequired()) {\n            ++$this->requiredCount;\n        } else {\n            $this->hasOptional = true;\n        }\n\n        $this->arguments[$argument->getName()] = $argument;\n    }\n\n    /**\n     * 根据名称或者位置获取参数\n     * @param string|int $name 参数名或者位置\n     * @return Argument 参数\n     * @throws \\InvalidArgumentException\n     */\n    public function getArgument($name)\n    {\n        if (!$this->hasArgument($name)) {\n            throw new \\InvalidArgumentException(sprintf('The \"%s\" argument does not exist.', $name));\n        }\n\n        $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;\n\n        return $arguments[$name];\n    }\n\n    /**\n     * 根据名称或位置检查是否具有某个参数\n     * @param string|int $name 参数名或者位置\n     * @return bool\n     * @api\n     */\n    public function hasArgument($name)\n    {\n        $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;\n\n        return isset($arguments[$name]);\n    }\n\n    /**\n     * 获取所有的参数\n     * @return Argument[] 参数数组\n     */\n    public function getArguments()\n    {\n        return $this->arguments;\n    }\n\n    /**\n     * 获取参数数量\n     * @return int\n     */\n    public function getArgumentCount()\n    {\n        return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);\n    }\n\n    /**\n     * 获取必填的参数的数量\n     * @return int\n     */\n    public function getArgumentRequiredCount()\n    {\n        return $this->requiredCount;\n    }\n\n    /**\n     * 获取参数默认值\n     * @return array\n     */\n    public function getArgumentDefaults()\n    {\n        $values = [];\n        foreach ($this->arguments as $argument) {\n            $values[$argument->getName()] = $argument->getDefault();\n        }\n\n        return $values;\n    }\n\n    /**\n     * 设置选项\n     * @param Option[] $options 选项数组\n     */\n    public function setOptions($options = [])\n    {\n        $this->options   = [];\n        $this->shortcuts = [];\n        $this->addOptions($options);\n    }\n\n    /**\n     * 添加选项\n     * @param Option[] $options 选项数组\n     * @api\n     */\n    public function addOptions($options = [])\n    {\n        foreach ($options as $option) {\n            $this->addOption($option);\n        }\n    }\n\n    /**\n     * 添加一个选项\n     * @param Option $option 选项\n     * @throws \\LogicException\n     * @api\n     */\n    public function addOption(Option $option)\n    {\n        if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {\n            throw new \\LogicException(sprintf('An option named \"%s\" already exists.', $option->getName()));\n        }\n\n        if ($option->getShortcut()) {\n            foreach (explode('|', $option->getShortcut()) as $shortcut) {\n                if (isset($this->shortcuts[$shortcut])\n                    && !$option->equals($this->options[$this->shortcuts[$shortcut]])\n                ) {\n                    throw new \\LogicException(sprintf('An option with shortcut \"%s\" already exists.', $shortcut));\n                }\n            }\n        }\n\n        $this->options[$option->getName()] = $option;\n        if ($option->getShortcut()) {\n            foreach (explode('|', $option->getShortcut()) as $shortcut) {\n                $this->shortcuts[$shortcut] = $option->getName();\n            }\n        }\n    }\n\n    /**\n     * 根据名称获取选项\n     * @param string $name 选项名\n     * @return Option\n     * @throws \\InvalidArgumentException\n     * @api\n     */\n    public function getOption($name)\n    {\n        if (!$this->hasOption($name)) {\n            throw new \\InvalidArgumentException(sprintf('The \"--%s\" option does not exist.', $name));\n        }\n\n        return $this->options[$name];\n    }\n\n    /**\n     * 根据名称检查是否有这个选项\n     * @param string $name 选项名\n     * @return bool\n     * @api\n     */\n    public function hasOption($name)\n    {\n        return isset($this->options[$name]);\n    }\n\n    /**\n     * 获取所有选项\n     * @return Option[]\n     * @api\n     */\n    public function getOptions()\n    {\n        return $this->options;\n    }\n\n    /**\n     * 根据名称检查某个选项是否有短名称\n     * @param string $name 短名称\n     * @return bool\n     */\n    public function hasShortcut($name)\n    {\n        return isset($this->shortcuts[$name]);\n    }\n\n    /**\n     * 根据短名称获取选项\n     * @param string $shortcut 短名称\n     * @return Option\n     */\n    public function getOptionForShortcut($shortcut)\n    {\n        return $this->getOption($this->shortcutToName($shortcut));\n    }\n\n    /**\n     * 获取所有选项的默认值\n     * @return array\n     */\n    public function getOptionDefaults()\n    {\n        $values = [];\n        foreach ($this->options as $option) {\n            $values[$option->getName()] = $option->getDefault();\n        }\n\n        return $values;\n    }\n\n    /**\n     * 根据短名称获取选项名\n     * @param string $shortcut 短名称\n     * @return string\n     * @throws \\InvalidArgumentException\n     */\n    private function shortcutToName($shortcut)\n    {\n        if (!isset($this->shortcuts[$shortcut])) {\n            throw new \\InvalidArgumentException(sprintf('The \"-%s\" option does not exist.', $shortcut));\n        }\n\n        return $this->shortcuts[$shortcut];\n    }\n\n    /**\n     * 获取该指令的介绍\n     * @param bool $short 是否简洁介绍\n     * @return string\n     */\n    public function getSynopsis($short = false)\n    {\n        $elements = [];\n\n        if ($short && $this->getOptions()) {\n            $elements[] = '[options]';\n        } elseif (!$short) {\n            foreach ($this->getOptions() as $option) {\n                $value = '';\n                if ($option->acceptValue()) {\n                    $value = sprintf(' %s%s%s', $option->isValueOptional() ? '[' : '', strtoupper($option->getName()), $option->isValueOptional() ? ']' : '');\n                }\n\n                $shortcut   = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';\n                $elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value);\n            }\n        }\n\n        if (count($elements) && $this->getArguments()) {\n            $elements[] = '[--]';\n        }\n\n        foreach ($this->getArguments() as $argument) {\n            $element = '<' . $argument->getName() . '>';\n            if (!$argument->isRequired()) {\n                $element = '[' . $element . ']';\n            } elseif ($argument->isArray()) {\n                $element .= ' (' . $element . ')';\n            }\n\n            if ($argument->isArray()) {\n                $element .= '...';\n            }\n\n            $elements[] = $element;\n        }\n\n        return implode(' ', $elements);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/input/Option.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\input;\n\nclass Option\n{\n\n    const VALUE_NONE     = 1;\n    const VALUE_REQUIRED = 2;\n    const VALUE_OPTIONAL = 4;\n    const VALUE_IS_ARRAY = 8;\n\n    private $name;\n    private $shortcut;\n    private $mode;\n    private $default;\n    private $description;\n\n    /**\n     * 构造方法\n     * @param string       $name        选项名\n     * @param string|array $shortcut    短名称,多个用|隔开或者使用数组\n     * @param int          $mode        选项类型(可选类型为 self::VALUE_*)\n     * @param string       $description 描述\n     * @param mixed        $default     默认值 (类型为 self::VALUE_REQUIRED 或者 self::VALUE_NONE 的时候必须为null)\n     * @throws \\InvalidArgumentException\n     */\n    public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)\n    {\n        if (0 === strpos($name, '--')) {\n            $name = substr($name, 2);\n        }\n\n        if (empty($name)) {\n            throw new \\InvalidArgumentException('An option name cannot be empty.');\n        }\n\n        if (empty($shortcut)) {\n            $shortcut = null;\n        }\n\n        if (null !== $shortcut) {\n            if (is_array($shortcut)) {\n                $shortcut = implode('|', $shortcut);\n            }\n            $shortcuts = preg_split('{(\\|)-?}', ltrim($shortcut, '-'));\n            $shortcuts = array_filter($shortcuts);\n            $shortcut  = implode('|', $shortcuts);\n\n            if (empty($shortcut)) {\n                throw new \\InvalidArgumentException('An option shortcut cannot be empty.');\n            }\n        }\n\n        if (null === $mode) {\n            $mode = self::VALUE_NONE;\n        } elseif (!is_int($mode) || $mode > 15 || $mode < 1) {\n            throw new \\InvalidArgumentException(sprintf('Option mode \"%s\" is not valid.', $mode));\n        }\n\n        $this->name        = $name;\n        $this->shortcut    = $shortcut;\n        $this->mode        = $mode;\n        $this->description = $description;\n\n        if ($this->isArray() && !$this->acceptValue()) {\n            throw new \\InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');\n        }\n\n        $this->setDefault($default);\n    }\n\n    /**\n     * 获取短名称\n     * @return string\n     */\n    public function getShortcut()\n    {\n        return $this->shortcut;\n    }\n\n    /**\n     * 获取选项名\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * 是否可以设置值\n     * @return bool 类型不是 self::VALUE_NONE 的时候返回true,其他均返回false\n     */\n    public function acceptValue()\n    {\n        return $this->isValueRequired() || $this->isValueOptional();\n    }\n\n    /**\n     * 是否必须\n     * @return bool 类型是 self::VALUE_REQUIRED 的时候返回true,其他均返回false\n     */\n    public function isValueRequired()\n    {\n        return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);\n    }\n\n    /**\n     * 是否可选\n     * @return bool 类型是 self::VALUE_OPTIONAL 的时候返回true,其他均返回false\n     */\n    public function isValueOptional()\n    {\n        return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);\n    }\n\n    /**\n     * 选项值是否接受数组\n     * @return bool 类型是 self::VALUE_IS_ARRAY 的时候返回true,其他均返回false\n     */\n    public function isArray()\n    {\n        return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);\n    }\n\n    /**\n     * 设置默认值\n     * @param mixed $default 默认值\n     * @throws \\LogicException\n     */\n    public function setDefault($default = null)\n    {\n        if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {\n            throw new \\LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');\n        }\n\n        if ($this->isArray()) {\n            if (null === $default) {\n                $default = [];\n            } elseif (!is_array($default)) {\n                throw new \\LogicException('A default value for an array option must be an array.');\n            }\n        }\n\n        $this->default = $this->acceptValue() ? $default : false;\n    }\n\n    /**\n     * 获取默认值\n     * @return mixed\n     */\n    public function getDefault()\n    {\n        return $this->default;\n    }\n\n    /**\n     * 获取描述文字\n     * @return string\n     */\n    public function getDescription()\n    {\n        return $this->description;\n    }\n\n    /**\n     * 检查所给选项是否是当前这个\n     * @param Option $option\n     * @return bool\n     */\n    public function equals(Option $option)\n    {\n        return $option->getName() === $this->getName()\n        && $option->getShortcut() === $this->getShortcut()\n        && $option->getDefault() === $this->getDefault()\n        && $option->isArray() === $this->isArray()\n        && $option->isValueRequired() === $this->isValueRequired()\n        && $option->isValueOptional() === $this->isValueOptional();\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/Ask.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output;\n\nuse think\\console\\Input;\nuse think\\console\\Output;\nuse think\\console\\output\\question\\Choice;\nuse think\\console\\output\\question\\Confirmation;\n\nclass Ask\n{\n    private static $stty;\n\n    private static $shell;\n\n    /** @var  Input */\n    protected $input;\n\n    /** @var  Output */\n    protected $output;\n\n    /** @var  Question */\n    protected $question;\n\n    public function __construct(Input $input, Output $output, Question $question)\n    {\n        $this->input    = $input;\n        $this->output   = $output;\n        $this->question = $question;\n    }\n\n    public function run()\n    {\n        if (!$this->input->isInteractive()) {\n            return $this->question->getDefault();\n        }\n\n        if (!$this->question->getValidator()) {\n            return $this->doAsk();\n        }\n\n        $that = $this;\n\n        $interviewer = function () use ($that) {\n            return $that->doAsk();\n        };\n\n        return $this->validateAttempts($interviewer);\n    }\n\n    protected function doAsk()\n    {\n        $this->writePrompt();\n\n        $inputStream  = STDIN;\n        $autocomplete = $this->question->getAutocompleterValues();\n\n        if (null === $autocomplete || !$this->hasSttyAvailable()) {\n            $ret = false;\n            if ($this->question->isHidden()) {\n                try {\n                    $ret = trim($this->getHiddenResponse($inputStream));\n                } catch (\\RuntimeException $e) {\n                    if (!$this->question->isHiddenFallback()) {\n                        throw $e;\n                    }\n                }\n            }\n\n            if (false === $ret) {\n                $ret = fgets($inputStream, 4096);\n                if (false === $ret) {\n                    throw new \\RuntimeException('Aborted');\n                }\n                $ret = trim($ret);\n            }\n        } else {\n            $ret = trim($this->autocomplete($inputStream));\n        }\n\n        $ret = strlen($ret) > 0 ? $ret : $this->question->getDefault();\n\n        if ($normalizer = $this->question->getNormalizer()) {\n            return $normalizer($ret);\n        }\n\n        return $ret;\n    }\n\n    private function autocomplete($inputStream)\n    {\n        $autocomplete = $this->question->getAutocompleterValues();\n        $ret          = '';\n\n        $i          = 0;\n        $ofs        = -1;\n        $matches    = $autocomplete;\n        $numMatches = count($matches);\n\n        $sttyMode = shell_exec('stty -g');\n\n        shell_exec('stty -icanon -echo');\n\n        while (!feof($inputStream)) {\n            $c = fread($inputStream, 1);\n\n            if (\"\\177\" === $c) {\n                if (0 === $numMatches && 0 !== $i) {\n                    --$i;\n                    $this->output->write(\"\\033[1D\");\n                }\n\n                if ($i === 0) {\n                    $ofs        = -1;\n                    $matches    = $autocomplete;\n                    $numMatches = count($matches);\n                } else {\n                    $numMatches = 0;\n                }\n\n                $ret = substr($ret, 0, $i);\n            } elseif (\"\\033\" === $c) {\n                $c .= fread($inputStream, 2);\n\n                if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {\n                    if ('A' === $c[2] && -1 === $ofs) {\n                        $ofs = 0;\n                    }\n\n                    if (0 === $numMatches) {\n                        continue;\n                    }\n\n                    $ofs += ('A' === $c[2]) ? -1 : 1;\n                    $ofs = ($numMatches + $ofs) % $numMatches;\n                }\n            } elseif (ord($c) < 32) {\n                if (\"\\t\" === $c || \"\\n\" === $c) {\n                    if ($numMatches > 0 && -1 !== $ofs) {\n                        $ret = $matches[$ofs];\n                        $this->output->write(substr($ret, $i));\n                        $i = strlen($ret);\n                    }\n\n                    if (\"\\n\" === $c) {\n                        $this->output->write($c);\n                        break;\n                    }\n\n                    $numMatches = 0;\n                }\n\n                continue;\n            } else {\n                $this->output->write($c);\n                $ret .= $c;\n                ++$i;\n\n                $numMatches = 0;\n                $ofs        = 0;\n\n                foreach ($autocomplete as $value) {\n                    if (0 === strpos($value, $ret) && $i !== strlen($value)) {\n                        $matches[$numMatches++] = $value;\n                    }\n                }\n            }\n\n            $this->output->write(\"\\033[K\");\n\n            if ($numMatches > 0 && -1 !== $ofs) {\n                $this->output->write(\"\\0337\");\n                $this->output->highlight(substr($matches[$ofs], $i));\n                $this->output->write(\"\\0338\");\n            }\n        }\n\n        shell_exec(sprintf('stty %s', $sttyMode));\n\n        return $ret;\n    }\n\n    protected function getHiddenResponse($inputStream)\n    {\n        if ('\\\\' === DIRECTORY_SEPARATOR) {\n            $exe = __DIR__ . '/../bin/hiddeninput.exe';\n\n            $value = rtrim(shell_exec($exe));\n            $this->output->writeln('');\n\n            if (isset($tmpExe)) {\n                unlink($tmpExe);\n            }\n\n            return $value;\n        }\n\n        if ($this->hasSttyAvailable()) {\n            $sttyMode = shell_exec('stty -g');\n\n            shell_exec('stty -echo');\n            $value = fgets($inputStream, 4096);\n            shell_exec(sprintf('stty %s', $sttyMode));\n\n            if (false === $value) {\n                throw new \\RuntimeException('Aborted');\n            }\n\n            $value = trim($value);\n            $this->output->writeln('');\n\n            return $value;\n        }\n\n        if (false !== $shell = $this->getShell()) {\n            $readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword';\n            $command = sprintf(\"/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \\$mypassword'\", $shell, $readCmd);\n            $value   = rtrim(shell_exec($command));\n            $this->output->writeln('');\n\n            return $value;\n        }\n\n        throw new \\RuntimeException('Unable to hide the response.');\n    }\n\n    protected function validateAttempts($interviewer)\n    {\n        /** @var \\Exception $error */\n        $error    = null;\n        $attempts = $this->question->getMaxAttempts();\n        while (null === $attempts || $attempts--) {\n            if (null !== $error) {\n                $this->output->error($error->getMessage());\n            }\n\n            try {\n                return call_user_func($this->question->getValidator(), $interviewer());\n            } catch (\\Exception $error) {\n            }\n        }\n\n        throw $error;\n    }\n\n    /**\n     * 显示问题的提示信息\n     */\n    protected function writePrompt()\n    {\n        $text    = $this->question->getQuestion();\n        $default = $this->question->getDefault();\n\n        switch (true) {\n            case null === $default:\n                $text = sprintf(' <info>%s</info>:', $text);\n\n                break;\n\n            case $this->question instanceof Confirmation:\n                $text = sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');\n\n                break;\n\n            case $this->question instanceof Choice && $this->question->isMultiselect():\n                $choices = $this->question->getChoices();\n                $default = explode(',', $default);\n\n                foreach ($default as $key => $value) {\n                    $default[$key] = $choices[trim($value)];\n                }\n\n                $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, implode(', ', $default));\n\n                break;\n\n            case $this->question instanceof Choice:\n                $choices = $this->question->getChoices();\n                $text    = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, $choices[$default]);\n\n                break;\n\n            default:\n                $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, $default);\n        }\n\n        $this->output->writeln($text);\n\n        if ($this->question instanceof Choice) {\n            $width = max(array_map('strlen', array_keys($this->question->getChoices())));\n\n            foreach ($this->question->getChoices() as $key => $value) {\n                $this->output->writeln(sprintf(\"  [<comment>%-${width}s</comment>] %s\", $key, $value));\n            }\n        }\n\n        $this->output->write(' > ');\n    }\n\n    private function getShell()\n    {\n        if (null !== self::$shell) {\n            return self::$shell;\n        }\n\n        self::$shell = false;\n\n        if (file_exists('/usr/bin/env')) {\n            $test = \"/usr/bin/env %s -c 'echo OK' 2> /dev/null\";\n            foreach (['bash', 'zsh', 'ksh', 'csh'] as $sh) {\n                if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {\n                    self::$shell = $sh;\n                    break;\n                }\n            }\n        }\n\n        return self::$shell;\n    }\n\n    private function hasSttyAvailable()\n    {\n        if (null !== self::$stty) {\n            return self::$stty;\n        }\n\n        exec('stty 2>&1', $output, $exitcode);\n\n        return self::$stty = $exitcode === 0;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/Descriptor.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output;\n\nuse think\\Console;\nuse think\\console\\Command;\nuse think\\console\\input\\Argument as InputArgument;\nuse think\\console\\input\\Definition as InputDefinition;\nuse think\\console\\input\\Option as InputOption;\nuse think\\console\\Output;\nuse think\\console\\output\\descriptor\\Console as ConsoleDescription;\n\nclass Descriptor\n{\n\n    /**\n     * @var Output\n     */\n    protected $output;\n\n    /**\n     * {@inheritdoc}\n     */\n    public function describe(Output $output, $object, array $options = [])\n    {\n        $this->output = $output;\n\n        switch (true) {\n            case $object instanceof InputArgument:\n                $this->describeInputArgument($object, $options);\n                break;\n            case $object instanceof InputOption:\n                $this->describeInputOption($object, $options);\n                break;\n            case $object instanceof InputDefinition:\n                $this->describeInputDefinition($object, $options);\n                break;\n            case $object instanceof Command:\n                $this->describeCommand($object, $options);\n                break;\n            case $object instanceof Console:\n                $this->describeConsole($object, $options);\n                break;\n            default:\n                throw new \\InvalidArgumentException(sprintf('Object of type \"%s\" is not describable.', get_class($object)));\n        }\n    }\n\n    /**\n     * 输出内容\n     * @param string $content\n     * @param bool   $decorated\n     */\n    protected function write($content, $decorated = false)\n    {\n        $this->output->write($content, false, $decorated ? Output::OUTPUT_NORMAL : Output::OUTPUT_RAW);\n    }\n\n    /**\n     * 描述参数\n     * @param InputArgument $argument\n     * @param array         $options\n     * @return string|mixed\n     */\n    protected function describeInputArgument(InputArgument $argument, array $options = [])\n    {\n        if (null !== $argument->getDefault()\n            && (!is_array($argument->getDefault())\n                || count($argument->getDefault()))\n        ) {\n            $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));\n        } else {\n            $default = '';\n        }\n\n        $totalWidth   = isset($options['total_width']) ? $options['total_width'] : strlen($argument->getName());\n        $spacingWidth = $totalWidth - strlen($argument->getName()) + 2;\n\n        $this->writeText(sprintf(\"  <info>%s</info>%s%s%s\", $argument->getName(), str_repeat(' ', $spacingWidth), // + 17 = 2 spaces + <info> + </info> + 2 spaces\n            preg_replace('/\\s*\\R\\s*/', PHP_EOL . str_repeat(' ', $totalWidth + 17), $argument->getDescription()), $default), $options);\n    }\n\n    /**\n     * 描述选项\n     * @param InputOption $option\n     * @param array       $options\n     * @return string|mixed\n     */\n    protected function describeInputOption(InputOption $option, array $options = [])\n    {\n        if ($option->acceptValue() && null !== $option->getDefault()\n            && (!is_array($option->getDefault())\n                || count($option->getDefault()))\n        ) {\n            $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));\n        } else {\n            $default = '';\n        }\n\n        $value = '';\n        if ($option->acceptValue()) {\n            $value = '=' . strtoupper($option->getName());\n\n            if ($option->isValueOptional()) {\n                $value = '[' . $value . ']';\n            }\n        }\n\n        $totalWidth = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions([$option]);\n        $synopsis   = sprintf('%s%s', $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : '    ', sprintf('--%s%s', $option->getName(), $value));\n\n        $spacingWidth = $totalWidth - strlen($synopsis) + 2;\n\n        $this->writeText(sprintf(\"  <info>%s</info>%s%s%s%s\", $synopsis, str_repeat(' ', $spacingWidth), // + 17 = 2 spaces + <info> + </info> + 2 spaces\n            preg_replace('/\\s*\\R\\s*/', \"\\n\" . str_repeat(' ', $totalWidth + 17), $option->getDescription()), $default, $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''), $options);\n    }\n\n    /**\n     * 描述输入\n     * @param InputDefinition $definition\n     * @param array           $options\n     * @return string|mixed\n     */\n    protected function describeInputDefinition(InputDefinition $definition, array $options = [])\n    {\n        $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());\n        foreach ($definition->getArguments() as $argument) {\n            $totalWidth = max($totalWidth, strlen($argument->getName()));\n        }\n\n        if ($definition->getArguments()) {\n            $this->writeText('<comment>Arguments:</comment>', $options);\n            $this->writeText(\"\\n\");\n            foreach ($definition->getArguments() as $argument) {\n                $this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth]));\n                $this->writeText(\"\\n\");\n            }\n        }\n\n        if ($definition->getArguments() && $definition->getOptions()) {\n            $this->writeText(\"\\n\");\n        }\n\n        if ($definition->getOptions()) {\n            $laterOptions = [];\n\n            $this->writeText('<comment>Options:</comment>', $options);\n            foreach ($definition->getOptions() as $option) {\n                if (strlen($option->getShortcut()) > 1) {\n                    $laterOptions[] = $option;\n                    continue;\n                }\n                $this->writeText(\"\\n\");\n                $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));\n            }\n            foreach ($laterOptions as $option) {\n                $this->writeText(\"\\n\");\n                $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));\n            }\n        }\n    }\n\n    /**\n     * 描述指令\n     * @param Command $command\n     * @param array   $options\n     * @return string|mixed\n     */\n    protected function describeCommand(Command $command, array $options = [])\n    {\n        $command->getSynopsis(true);\n        $command->getSynopsis(false);\n        $command->mergeConsoleDefinition(false);\n\n        $this->writeText('<comment>Usage:</comment>', $options);\n        foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) {\n            $this->writeText(\"\\n\");\n            $this->writeText('  ' . $usage, $options);\n        }\n        $this->writeText(\"\\n\");\n\n        $definition = $command->getNativeDefinition();\n        if ($definition->getOptions() || $definition->getArguments()) {\n            $this->writeText(\"\\n\");\n            $this->describeInputDefinition($definition, $options);\n            $this->writeText(\"\\n\");\n        }\n\n        if ($help = $command->getProcessedHelp()) {\n            $this->writeText(\"\\n\");\n            $this->writeText('<comment>Help:</comment>', $options);\n            $this->writeText(\"\\n\");\n            $this->writeText(' ' . str_replace(\"\\n\", \"\\n \", $help), $options);\n            $this->writeText(\"\\n\");\n        }\n    }\n\n    /**\n     * 描述控制台\n     * @param Console $console\n     * @param array   $options\n     * @return string|mixed\n     */\n    protected function describeConsole(Console $console, array $options = [])\n    {\n        $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;\n        $description        = new ConsoleDescription($console, $describedNamespace);\n\n        if (isset($options['raw_text']) && $options['raw_text']) {\n            $width = $this->getColumnWidth($description->getCommands());\n\n            foreach ($description->getCommands() as $command) {\n                $this->writeText(sprintf(\"%-${width}s %s\", $command->getName(), $command->getDescription()), $options);\n                $this->writeText(\"\\n\");\n            }\n        } else {\n            if ('' != $help = $console->getHelp()) {\n                $this->writeText(\"$help\\n\\n\", $options);\n            }\n\n            $this->writeText(\"<comment>Usage:</comment>\\n\", $options);\n            $this->writeText(\"  command [options] [arguments]\\n\\n\", $options);\n\n            $this->describeInputDefinition(new InputDefinition($console->getDefinition()->getOptions()), $options);\n\n            $this->writeText(\"\\n\");\n            $this->writeText(\"\\n\");\n\n            $width = $this->getColumnWidth($description->getCommands());\n\n            if ($describedNamespace) {\n                $this->writeText(sprintf('<comment>Available commands for the \"%s\" namespace:</comment>', $describedNamespace), $options);\n            } else {\n                $this->writeText('<comment>Available commands:</comment>', $options);\n            }\n\n            // add commands by namespace\n            foreach ($description->getNamespaces() as $namespace) {\n                if (!$describedNamespace && ConsoleDescription::GLOBAL_NAMESPACE !== $namespace['id']) {\n                    $this->writeText(\"\\n\");\n                    $this->writeText(' <comment>' . $namespace['id'] . '</comment>', $options);\n                }\n\n                foreach ($namespace['commands'] as $name) {\n                    $this->writeText(\"\\n\");\n                    $spacingWidth = $width - strlen($name);\n                    $this->writeText(sprintf(\"  <info>%s</info>%s%s\", $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)\n                            ->getDescription()), $options);\n                }\n            }\n\n            $this->writeText(\"\\n\");\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    private function writeText($content, array $options = [])\n    {\n        $this->write(isset($options['raw_text'])\n            && $options['raw_text'] ? strip_tags($content) : $content, isset($options['raw_output']) ? !$options['raw_output'] : true);\n    }\n\n    /**\n     * 格式化\n     * @param mixed $default\n     * @return string\n     */\n    private function formatDefaultValue($default)\n    {\n        return json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);\n    }\n\n    /**\n     * @param Command[] $commands\n     * @return int\n     */\n    private function getColumnWidth(array $commands)\n    {\n        $width = 0;\n        foreach ($commands as $command) {\n            $width = strlen($command->getName()) > $width ? strlen($command->getName()) : $width;\n        }\n\n        return $width + 2;\n    }\n\n    /**\n     * @param InputOption[] $options\n     * @return int\n     */\n    private function calculateTotalWidthForOptions($options)\n    {\n        $totalWidth = 0;\n        foreach ($options as $option) {\n            $nameLength = 4 + strlen($option->getName()) + 2; // - + shortcut + , + whitespace + name + --\n\n            if ($option->acceptValue()) {\n                $valueLength = 1 + strlen($option->getName()); // = + value\n                $valueLength += $option->isValueOptional() ? 2 : 0; // [ + ]\n\n                $nameLength += $valueLength;\n            }\n            $totalWidth = max($totalWidth, $nameLength);\n        }\n\n        return $totalWidth;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/Formatter.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\nnamespace think\\console\\output;\n\nuse think\\console\\output\\formatter\\Stack as StyleStack;\nuse think\\console\\output\\formatter\\Style;\n\nclass Formatter\n{\n\n    private $decorated = false;\n    private $styles    = [];\n    private $styleStack;\n\n    /**\n     * 转义\n     * @param string $text\n     * @return string\n     */\n    public static function escape($text)\n    {\n        return preg_replace('/([^\\\\\\\\]?)</is', '$1\\\\<', $text);\n    }\n\n    /**\n     * 初始化命令行输出格式\n     */\n    public function __construct()\n    {\n        $this->setStyle('error', new Style('white', 'red'));\n        $this->setStyle('info', new Style('green'));\n        $this->setStyle('comment', new Style('yellow'));\n        $this->setStyle('question', new Style('black', 'cyan'));\n        $this->setStyle('highlight', new Style('red'));\n        $this->setStyle('warning', new Style('black', 'yellow'));\n\n        $this->styleStack = new StyleStack();\n    }\n\n    /**\n     * 设置外观标识\n     * @param bool $decorated 是否美化文字\n     */\n    public function setDecorated($decorated)\n    {\n        $this->decorated = (bool) $decorated;\n    }\n\n    /**\n     * 获取外观标识\n     * @return bool\n     */\n    public function isDecorated()\n    {\n        return $this->decorated;\n    }\n\n    /**\n     * 添加一个新样式\n     * @param string $name  样式名\n     * @param Style  $style 样式实例\n     */\n    public function setStyle($name, Style $style)\n    {\n        $this->styles[strtolower($name)] = $style;\n    }\n\n    /**\n     * 是否有这个样式\n     * @param string $name\n     * @return bool\n     */\n    public function hasStyle($name)\n    {\n        return isset($this->styles[strtolower($name)]);\n    }\n\n    /**\n     * 获取样式\n     * @param string $name\n     * @return Style\n     * @throws \\InvalidArgumentException\n     */\n    public function getStyle($name)\n    {\n        if (!$this->hasStyle($name)) {\n            throw new \\InvalidArgumentException(sprintf('Undefined style: %s', $name));\n        }\n\n        return $this->styles[strtolower($name)];\n    }\n\n    /**\n     * 使用所给的样式格式化文字\n     * @param string $message 文字\n     * @return string\n     */\n    public function format($message)\n    {\n        $offset   = 0;\n        $output   = '';\n        $tagRegex = '[a-z][a-z0-9_=;-]*';\n        preg_match_all(\"#<(($tagRegex) | /($tagRegex)?)>#isx\", $message, $matches, PREG_OFFSET_CAPTURE);\n        foreach ($matches[0] as $i => $match) {\n            $pos  = $match[1];\n            $text = $match[0];\n\n            if (0 != $pos && '\\\\' == $message[$pos - 1]) {\n                continue;\n            }\n\n            $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));\n            $offset = $pos + strlen($text);\n\n            if ($open = '/' != $text[1]) {\n                $tag = $matches[1][$i][0];\n            } else {\n                $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : '';\n            }\n\n            if (!$open && !$tag) {\n                // </>\n                $this->styleStack->pop();\n            } elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {\n                $output .= $this->applyCurrentStyle($text);\n            } elseif ($open) {\n                $this->styleStack->push($style);\n            } else {\n                $this->styleStack->pop($style);\n            }\n        }\n\n        $output .= $this->applyCurrentStyle(substr($message, $offset));\n\n        return str_replace('\\\\<', '<', $output);\n    }\n\n    /**\n     * @return StyleStack\n     */\n    public function getStyleStack()\n    {\n        return $this->styleStack;\n    }\n\n    /**\n     * 根据字符串创建新的样式实例\n     * @param string $string\n     * @return Style|bool\n     */\n    private function createStyleFromString($string)\n    {\n        if (isset($this->styles[$string])) {\n            return $this->styles[$string];\n        }\n\n        if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) {\n            return false;\n        }\n\n        $style = new Style();\n        foreach ($matches as $match) {\n            array_shift($match);\n\n            if ('fg' == $match[0]) {\n                $style->setForeground($match[1]);\n            } elseif ('bg' == $match[0]) {\n                $style->setBackground($match[1]);\n            } else {\n                try {\n                    $style->setOption($match[1]);\n                } catch (\\InvalidArgumentException $e) {\n                    return false;\n                }\n            }\n        }\n\n        return $style;\n    }\n\n    /**\n     * 从堆栈应用样式到文字\n     * @param string $text 文字\n     * @return string\n     */\n    private function applyCurrentStyle($text)\n    {\n        return $this->isDecorated() && strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/Question.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output;\n\nclass Question\n{\n\n    private $question;\n    private $attempts;\n    private $hidden         = false;\n    private $hiddenFallback = true;\n    private $autocompleterValues;\n    private $validator;\n    private $default;\n    private $normalizer;\n\n    /**\n     * 构造方法\n     * @param string $question 问题\n     * @param mixed  $default  默认答案\n     */\n    public function __construct($question, $default = null)\n    {\n        $this->question = $question;\n        $this->default  = $default;\n    }\n\n    /**\n     * 获取问题\n     * @return string\n     */\n    public function getQuestion()\n    {\n        return $this->question;\n    }\n\n    /**\n     * 获取默认答案\n     * @return mixed\n     */\n    public function getDefault()\n    {\n        return $this->default;\n    }\n\n    /**\n     * 是否隐藏答案\n     * @return bool\n     */\n    public function isHidden()\n    {\n        return $this->hidden;\n    }\n\n    /**\n     * 隐藏答案\n     * @param bool $hidden\n     * @return Question\n     */\n    public function setHidden($hidden)\n    {\n        if ($this->autocompleterValues) {\n            throw new \\LogicException('A hidden question cannot use the autocompleter.');\n        }\n\n        $this->hidden = (bool) $hidden;\n\n        return $this;\n    }\n\n    /**\n     * 不能被隐藏是否撤销\n     * @return bool\n     */\n    public function isHiddenFallback()\n    {\n        return $this->hiddenFallback;\n    }\n\n    /**\n     * 设置不能被隐藏的时候的操作\n     * @param bool $fallback\n     * @return Question\n     */\n    public function setHiddenFallback($fallback)\n    {\n        $this->hiddenFallback = (bool) $fallback;\n\n        return $this;\n    }\n\n    /**\n     * 获取自动完成\n     * @return null|array|\\Traversable\n     */\n    public function getAutocompleterValues()\n    {\n        return $this->autocompleterValues;\n    }\n\n    /**\n     * 设置自动完成的值\n     * @param null|array|\\Traversable $values\n     * @return Question\n     * @throws \\InvalidArgumentException\n     * @throws \\LogicException\n     */\n    public function setAutocompleterValues($values)\n    {\n        if (is_array($values) && $this->isAssoc($values)) {\n            $values = array_merge(array_keys($values), array_values($values));\n        }\n\n        if (null !== $values && !is_array($values)) {\n            if (!$values instanceof \\Traversable || $values instanceof \\Countable) {\n                throw new \\InvalidArgumentException('Autocompleter values can be either an array, `null` or an object implementing both `Countable` and `Traversable` interfaces.');\n            }\n        }\n\n        if ($this->hidden) {\n            throw new \\LogicException('A hidden question cannot use the autocompleter.');\n        }\n\n        $this->autocompleterValues = $values;\n\n        return $this;\n    }\n\n    /**\n     * 设置答案的验证器\n     * @param null|callable $validator\n     * @return Question The current instance\n     */\n    public function setValidator($validator)\n    {\n        $this->validator = $validator;\n\n        return $this;\n    }\n\n    /**\n     * 获取验证器\n     * @return null|callable\n     */\n    public function getValidator()\n    {\n        return $this->validator;\n    }\n\n    /**\n     * 设置最大重试次数\n     * @param null|int $attempts\n     * @return Question\n     * @throws \\InvalidArgumentException\n     */\n    public function setMaxAttempts($attempts)\n    {\n        if (null !== $attempts && $attempts < 1) {\n            throw new \\InvalidArgumentException('Maximum number of attempts must be a positive value.');\n        }\n\n        $this->attempts = $attempts;\n\n        return $this;\n    }\n\n    /**\n     * 获取最大重试次数\n     * @return null|int\n     */\n    public function getMaxAttempts()\n    {\n        return $this->attempts;\n    }\n\n    /**\n     * 设置响应的回调\n     * @param string|\\Closure $normalizer\n     * @return Question\n     */\n    public function setNormalizer($normalizer)\n    {\n        $this->normalizer = $normalizer;\n\n        return $this;\n    }\n\n    /**\n     * 获取响应回调\n     * The normalizer can ba a callable (a string), a closure or a class implementing __invoke.\n     * @return string|\\Closure\n     */\n    public function getNormalizer()\n    {\n        return $this->normalizer;\n    }\n\n    protected function isAssoc($array)\n    {\n        return (bool) count(array_filter(array_keys($array), 'is_string'));\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/descriptor/Console.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output\\descriptor;\n\nuse think\\Console as ThinkConsole;\nuse think\\console\\Command;\n\nclass Console\n{\n\n    const GLOBAL_NAMESPACE = '_global';\n\n    /**\n     * @var ThinkConsole\n     */\n    private $console;\n\n    /**\n     * @var null|string\n     */\n    private $namespace;\n\n    /**\n     * @var array\n     */\n    private $namespaces;\n\n    /**\n     * @var Command[]\n     */\n    private $commands;\n\n    /**\n     * @var Command[]\n     */\n    private $aliases;\n\n    /**\n     * 构造方法\n     * @param ThinkConsole $console\n     * @param string|null  $namespace\n     */\n    public function __construct(ThinkConsole $console, $namespace = null)\n    {\n        $this->console   = $console;\n        $this->namespace = $namespace;\n    }\n\n    /**\n     * @return array\n     */\n    public function getNamespaces()\n    {\n        if (null === $this->namespaces) {\n            $this->inspectConsole();\n        }\n\n        return $this->namespaces;\n    }\n\n    /**\n     * @return Command[]\n     */\n    public function getCommands()\n    {\n        if (null === $this->commands) {\n            $this->inspectConsole();\n        }\n\n        return $this->commands;\n    }\n\n    /**\n     * @param string $name\n     * @return Command\n     * @throws \\InvalidArgumentException\n     */\n    public function getCommand($name)\n    {\n        if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {\n            throw new \\InvalidArgumentException(sprintf('Command %s does not exist.', $name));\n        }\n\n        return isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name];\n    }\n\n    private function inspectConsole()\n    {\n        $this->commands   = [];\n        $this->namespaces = [];\n\n        $all = $this->console->all($this->namespace ? $this->console->findNamespace($this->namespace) : null);\n        foreach ($this->sortCommands($all) as $namespace => $commands) {\n            $names = [];\n\n            /** @var Command $command */\n            foreach ($commands as $name => $command) {\n                if (!$command->getName()) {\n                    continue;\n                }\n\n                if ($command->getName() === $name) {\n                    $this->commands[$name] = $command;\n                } else {\n                    $this->aliases[$name] = $command;\n                }\n\n                $names[] = $name;\n            }\n\n            $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names];\n        }\n    }\n\n    /**\n     * @param array $commands\n     * @return array\n     */\n    private function sortCommands(array $commands)\n    {\n        $namespacedCommands = [];\n        foreach ($commands as $name => $command) {\n            $key = $this->console->extractNamespace($name, 1);\n            if (!$key) {\n                $key = self::GLOBAL_NAMESPACE;\n            }\n\n            $namespacedCommands[$key][$name] = $command;\n        }\n        ksort($namespacedCommands);\n\n        foreach ($namespacedCommands as &$commandsSet) {\n            ksort($commandsSet);\n        }\n        // unset reference to keep scope clear\n        unset($commandsSet);\n\n        return $namespacedCommands;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/driver/Buffer.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output\\driver;\n\nuse think\\console\\Output;\n\nclass Buffer\n{\n    /**\n     * @var string\n     */\n    private $buffer = '';\n\n    public function __construct(Output $output)\n    {\n        // do nothing\n    }\n\n    public function fetch()\n    {\n        $content      = $this->buffer;\n        $this->buffer = '';\n        return $content;\n    }\n\n    public function write($messages, $newline = false, $options = Output::OUTPUT_NORMAL)\n    {\n        $messages = (array) $messages;\n\n        foreach ($messages as $message) {\n            $this->buffer .= $message;\n        }\n        if ($newline) {\n            $this->buffer .= \"\\n\";\n        }\n    }\n\n    public function renderException(\\Exception $e)\n    {\n        // do nothing\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/driver/Console.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output\\driver;\n\nuse think\\console\\Output;\nuse think\\console\\output\\Formatter;\n\nclass Console\n{\n\n    /** @var  Resource */\n    private $stdout;\n\n    /** @var  Formatter */\n    private $formatter;\n\n    private $terminalDimensions;\n\n    /** @var  Output */\n    private $output;\n\n    public function __construct(Output $output)\n    {\n        $this->output    = $output;\n        $this->formatter = new Formatter();\n        $this->stdout    = $this->openOutputStream();\n        $decorated       = $this->hasColorSupport($this->stdout);\n        $this->formatter->setDecorated($decorated);\n    }\n\n    public function getFormatter()\n    {\n        return $this->formatter;\n    }\n\n    public function setDecorated($decorated)\n    {\n        $this->formatter->setDecorated($decorated);\n    }\n\n    public function write($messages, $newline = false, $type = Output::OUTPUT_NORMAL, $stream = null)\n    {\n        if (Output::VERBOSITY_QUIET === $this->output->getVerbosity()) {\n            return;\n        }\n\n        $messages = (array) $messages;\n\n        foreach ($messages as $message) {\n            switch ($type) {\n                case Output::OUTPUT_NORMAL:\n                    $message = $this->formatter->format($message);\n                    break;\n                case Output::OUTPUT_RAW:\n                    break;\n                case Output::OUTPUT_PLAIN:\n                    $message = strip_tags($this->formatter->format($message));\n                    break;\n                default:\n                    throw new \\InvalidArgumentException(sprintf('Unknown output type given (%s)', $type));\n            }\n\n            $this->doWrite($message, $newline, $stream);\n        }\n    }\n\n    public function renderException(\\Exception $e)\n    {\n        $stderr    = $this->openErrorStream();\n        $decorated = $this->hasColorSupport($stderr);\n        $this->formatter->setDecorated($decorated);\n\n        do {\n            $title = sprintf('  [%s]  ', get_class($e));\n\n            $len = $this->stringWidth($title);\n\n            $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;\n\n            if (defined('HHVM_VERSION') && $width > 1 << 31) {\n                $width = 1 << 31;\n            }\n            $lines = [];\n            foreach (preg_split('/\\r?\\n/', $e->getMessage()) as $line) {\n                foreach ($this->splitStringByWidth($line, $width - 4) as $line) {\n\n                    $lineLength = $this->stringWidth(preg_replace('/\u001b\\[[^m]*m/', '', $line)) + 4;\n                    $lines[]    = [$line, $lineLength];\n\n                    $len = max($lineLength, $len);\n                }\n            }\n\n            $messages   = ['', ''];\n            $messages[] = $emptyLine = sprintf('<error>%s</error>', str_repeat(' ', $len));\n            $messages[] = sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title))));\n            foreach ($lines as $line) {\n                $messages[] = sprintf('<error>  %s  %s</error>', $line[0], str_repeat(' ', $len - $line[1]));\n            }\n            $messages[] = $emptyLine;\n            $messages[] = '';\n            $messages[] = '';\n\n            $this->write($messages, true, Output::OUTPUT_NORMAL, $stderr);\n\n            if (Output::VERBOSITY_VERBOSE <= $this->output->getVerbosity()) {\n                $this->write('<comment>Exception trace:</comment>', true, Output::OUTPUT_NORMAL, $stderr);\n\n                // exception related properties\n                $trace = $e->getTrace();\n                array_unshift($trace, [\n                    'function' => '',\n                    'file'     => $e->getFile() !== null ? $e->getFile() : 'n/a',\n                    'line'     => $e->getLine() !== null ? $e->getLine() : 'n/a',\n                    'args'     => [],\n                ]);\n\n                for ($i = 0, $count = count($trace); $i < $count; ++$i) {\n                    $class    = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';\n                    $type     = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';\n                    $function = $trace[$i]['function'];\n                    $file     = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';\n                    $line     = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';\n\n                    $this->write(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line), true, Output::OUTPUT_NORMAL, $stderr);\n                }\n\n                $this->write('', true, Output::OUTPUT_NORMAL, $stderr);\n                $this->write('', true, Output::OUTPUT_NORMAL, $stderr);\n            }\n        } while ($e = $e->getPrevious());\n\n    }\n\n    /**\n     * 获取终端宽度\n     * @return int|null\n     */\n    protected function getTerminalWidth()\n    {\n        $dimensions = $this->getTerminalDimensions();\n\n        return $dimensions[0];\n    }\n\n    /**\n     * 获取终端高度\n     * @return int|null\n     */\n    protected function getTerminalHeight()\n    {\n        $dimensions = $this->getTerminalDimensions();\n\n        return $dimensions[1];\n    }\n\n    /**\n     * 获取当前终端的尺寸\n     * @return array\n     */\n    public function getTerminalDimensions()\n    {\n        if ($this->terminalDimensions) {\n            return $this->terminalDimensions;\n        }\n\n        if ('\\\\' === DS) {\n            if (preg_match('/^(\\d+)x\\d+ \\(\\d+x(\\d+)\\)$/', trim(getenv('ANSICON')), $matches)) {\n                return [(int) $matches[1], (int) $matches[2]];\n            }\n            if (preg_match('/^(\\d+)x(\\d+)$/', $this->getMode(), $matches)) {\n                return [(int) $matches[1], (int) $matches[2]];\n            }\n        }\n\n        if ($sttyString = $this->getSttyColumns()) {\n            if (preg_match('/rows.(\\d+);.columns.(\\d+);/i', $sttyString, $matches)) {\n                return [(int) $matches[2], (int) $matches[1]];\n            }\n            if (preg_match('/;.(\\d+).rows;.(\\d+).columns/i', $sttyString, $matches)) {\n                return [(int) $matches[2], (int) $matches[1]];\n            }\n        }\n\n        return [null, null];\n    }\n\n    /**\n     * 获取stty列数\n     * @return string\n     */\n    private function getSttyColumns()\n    {\n        if (!function_exists('proc_open')) {\n            return;\n        }\n\n        $descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];\n        $process        = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, ['suppress_errors' => true]);\n        if (is_resource($process)) {\n            $info = stream_get_contents($pipes[1]);\n            fclose($pipes[1]);\n            fclose($pipes[2]);\n            proc_close($process);\n\n            return $info;\n        }\n        return;\n    }\n\n    /**\n     * 获取终端模式\n     * @return string <width>x<height> 或 null\n     */\n    private function getMode()\n    {\n        if (!function_exists('proc_open')) {\n            return;\n        }\n\n        $descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];\n        $process        = proc_open('mode CON', $descriptorspec, $pipes, null, null, ['suppress_errors' => true]);\n        if (is_resource($process)) {\n            $info = stream_get_contents($pipes[1]);\n            fclose($pipes[1]);\n            fclose($pipes[2]);\n            proc_close($process);\n\n            if (preg_match('/--------+\\r?\\n.+?(\\d+)\\r?\\n.+?(\\d+)\\r?\\n/', $info, $matches)) {\n                return $matches[2] . 'x' . $matches[1];\n            }\n        }\n        return;\n    }\n\n    private function stringWidth($string)\n    {\n        if (!function_exists('mb_strwidth')) {\n            return strlen($string);\n        }\n\n        if (false === $encoding = mb_detect_encoding($string)) {\n            return strlen($string);\n        }\n\n        return mb_strwidth($string, $encoding);\n    }\n\n    private function splitStringByWidth($string, $width)\n    {\n        if (!function_exists('mb_strwidth')) {\n            return str_split($string, $width);\n        }\n\n        if (false === $encoding = mb_detect_encoding($string)) {\n            return str_split($string, $width);\n        }\n\n        $utf8String = mb_convert_encoding($string, 'utf8', $encoding);\n        $lines      = [];\n        $line       = '';\n        foreach (preg_split('//u', $utf8String) as $char) {\n            if (mb_strwidth($line . $char, 'utf8') <= $width) {\n                $line .= $char;\n                continue;\n            }\n            $lines[] = str_pad($line, $width);\n            $line    = $char;\n        }\n        if (strlen($line)) {\n            $lines[] = count($lines) ? str_pad($line, $width) : $line;\n        }\n\n        mb_convert_variables($encoding, 'utf8', $lines);\n\n        return $lines;\n    }\n\n    private function isRunningOS400()\n    {\n        $checks = [\n            function_exists('php_uname') ? php_uname('s') : '',\n            getenv('OSTYPE'),\n            PHP_OS,\n        ];\n        return false !== stripos(implode(';', $checks), 'OS400');\n    }\n\n    /**\n     * 当前环境是否支持写入控制台输出到stdout.\n     *\n     * @return bool\n     */\n    protected function hasStdoutSupport()\n    {\n        return false === $this->isRunningOS400();\n    }\n\n    /**\n     * 当前环境是否支持写入控制台输出到stderr.\n     *\n     * @return bool\n     */\n    protected function hasStderrSupport()\n    {\n        return false === $this->isRunningOS400();\n    }\n\n    /**\n     * @return resource\n     */\n    private function openOutputStream()\n    {\n        if (!$this->hasStdoutSupport()) {\n            return fopen('php://output', 'w');\n        }\n        return @fopen('php://stdout', 'w') ?: fopen('php://output', 'w');\n    }\n\n    /**\n     * @return resource\n     */\n    private function openErrorStream()\n    {\n        return fopen($this->hasStderrSupport() ? 'php://stderr' : 'php://output', 'w');\n    }\n\n    /**\n     * 将消息写入到输出。\n     * @param string $message 消息\n     * @param bool   $newline 是否另起一行\n     * @param null   $stream\n     */\n    protected function doWrite($message, $newline, $stream = null)\n    {\n        if (null === $stream) {\n            $stream = $this->stdout;\n        }\n        if (false === @fwrite($stream, $message . ($newline ? PHP_EOL : ''))) {\n            throw new \\RuntimeException('Unable to write output.');\n        }\n\n        fflush($stream);\n    }\n\n    /**\n     * 是否支持着色\n     * @param $stream\n     * @return bool\n     */\n    protected function hasColorSupport($stream)\n    {\n        if (DIRECTORY_SEPARATOR === '\\\\') {\n            return\n            '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR . '.' . PHP_WINDOWS_VERSION_MINOR . '.' . PHP_WINDOWS_VERSION_BUILD\n            || false !== getenv('ANSICON')\n            || 'ON' === getenv('ConEmuANSI')\n            || 'xterm' === getenv('TERM');\n        }\n\n        return function_exists('posix_isatty') && @posix_isatty($stream);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/driver/Nothing.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output\\driver;\n\nuse think\\console\\Output;\n\nclass Nothing\n{\n\n    public function __construct(Output $output)\n    {\n        // do nothing\n    }\n\n    public function write($messages, $newline = false, $options = Output::OUTPUT_NORMAL)\n    {\n        // do nothing\n    }\n\n    public function renderException(\\Exception $e)\n    {\n        // do nothing\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/formatter/Stack.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output\\formatter;\n\nclass Stack\n{\n\n    /**\n     * @var Style[]\n     */\n    private $styles;\n\n    /**\n     * @var Style\n     */\n    private $emptyStyle;\n\n    /**\n     * 构造方法\n     * @param Style|null $emptyStyle\n     */\n    public function __construct(Style $emptyStyle = null)\n    {\n        $this->emptyStyle = $emptyStyle ?: new Style();\n        $this->reset();\n    }\n\n    /**\n     * 重置堆栈\n     */\n    public function reset()\n    {\n        $this->styles = [];\n    }\n\n    /**\n     * 推一个样式进入堆栈\n     * @param Style $style\n     */\n    public function push(Style $style)\n    {\n        $this->styles[] = $style;\n    }\n\n    /**\n     * 从堆栈中弹出一个样式\n     * @param Style|null $style\n     * @return Style\n     * @throws \\InvalidArgumentException\n     */\n    public function pop(Style $style = null)\n    {\n        if (empty($this->styles)) {\n            return $this->emptyStyle;\n        }\n\n        if (null === $style) {\n            return array_pop($this->styles);\n        }\n\n        /**\n         * @var int   $index\n         * @var Style $stackedStyle\n         */\n        foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {\n            if ($style->apply('') === $stackedStyle->apply('')) {\n                $this->styles = array_slice($this->styles, 0, $index);\n\n                return $stackedStyle;\n            }\n        }\n\n        throw new \\InvalidArgumentException('Incorrectly nested style tag found.');\n    }\n\n    /**\n     * 计算堆栈的当前样式。\n     * @return Style\n     */\n    public function getCurrent()\n    {\n        if (empty($this->styles)) {\n            return $this->emptyStyle;\n        }\n\n        return $this->styles[count($this->styles) - 1];\n    }\n\n    /**\n     * @param Style $emptyStyle\n     * @return Stack\n     */\n    public function setEmptyStyle(Style $emptyStyle)\n    {\n        $this->emptyStyle = $emptyStyle;\n\n        return $this;\n    }\n\n    /**\n     * @return Style\n     */\n    public function getEmptyStyle()\n    {\n        return $this->emptyStyle;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/formatter/Style.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output\\formatter;\n\nclass Style\n{\n\n    private static $availableForegroundColors = [\n        'black'   => ['set' => 30, 'unset' => 39],\n        'red'     => ['set' => 31, 'unset' => 39],\n        'green'   => ['set' => 32, 'unset' => 39],\n        'yellow'  => ['set' => 33, 'unset' => 39],\n        'blue'    => ['set' => 34, 'unset' => 39],\n        'magenta' => ['set' => 35, 'unset' => 39],\n        'cyan'    => ['set' => 36, 'unset' => 39],\n        'white'   => ['set' => 37, 'unset' => 39],\n    ];\n    private static $availableBackgroundColors = [\n        'black'   => ['set' => 40, 'unset' => 49],\n        'red'     => ['set' => 41, 'unset' => 49],\n        'green'   => ['set' => 42, 'unset' => 49],\n        'yellow'  => ['set' => 43, 'unset' => 49],\n        'blue'    => ['set' => 44, 'unset' => 49],\n        'magenta' => ['set' => 45, 'unset' => 49],\n        'cyan'    => ['set' => 46, 'unset' => 49],\n        'white'   => ['set' => 47, 'unset' => 49],\n    ];\n    private static $availableOptions = [\n        'bold'       => ['set' => 1, 'unset' => 22],\n        'underscore' => ['set' => 4, 'unset' => 24],\n        'blink'      => ['set' => 5, 'unset' => 25],\n        'reverse'    => ['set' => 7, 'unset' => 27],\n        'conceal'    => ['set' => 8, 'unset' => 28],\n    ];\n\n    private $foreground;\n    private $background;\n    private $options = [];\n\n    /**\n     * 初始化输出的样式\n     * @param string|null $foreground 字体颜色\n     * @param string|null $background 背景色\n     * @param array       $options    格式\n     * @api\n     */\n    public function __construct($foreground = null, $background = null, array $options = [])\n    {\n        if (null !== $foreground) {\n            $this->setForeground($foreground);\n        }\n        if (null !== $background) {\n            $this->setBackground($background);\n        }\n        if (count($options)) {\n            $this->setOptions($options);\n        }\n    }\n\n    /**\n     * 设置字体颜色\n     * @param string|null $color 颜色名\n     * @throws \\InvalidArgumentException\n     * @api\n     */\n    public function setForeground($color = null)\n    {\n        if (null === $color) {\n            $this->foreground = null;\n\n            return;\n        }\n\n        if (!isset(static::$availableForegroundColors[$color])) {\n            throw new \\InvalidArgumentException(sprintf('Invalid foreground color specified: \"%s\". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableForegroundColors))));\n        }\n\n        $this->foreground = static::$availableForegroundColors[$color];\n    }\n\n    /**\n     * 设置背景色\n     * @param string|null $color 颜色名\n     * @throws \\InvalidArgumentException\n     * @api\n     */\n    public function setBackground($color = null)\n    {\n        if (null === $color) {\n            $this->background = null;\n\n            return;\n        }\n\n        if (!isset(static::$availableBackgroundColors[$color])) {\n            throw new \\InvalidArgumentException(sprintf('Invalid background color specified: \"%s\". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableBackgroundColors))));\n        }\n\n        $this->background = static::$availableBackgroundColors[$color];\n    }\n\n    /**\n     * 设置字体格式\n     * @param string $option 格式名\n     * @throws \\InvalidArgumentException When the option name isn't defined\n     * @api\n     */\n    public function setOption($option)\n    {\n        if (!isset(static::$availableOptions[$option])) {\n            throw new \\InvalidArgumentException(sprintf('Invalid option specified: \"%s\". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));\n        }\n\n        if (!in_array(static::$availableOptions[$option], $this->options)) {\n            $this->options[] = static::$availableOptions[$option];\n        }\n    }\n\n    /**\n     * 重置字体格式\n     * @param string $option 格式名\n     * @throws \\InvalidArgumentException\n     */\n    public function unsetOption($option)\n    {\n        if (!isset(static::$availableOptions[$option])) {\n            throw new \\InvalidArgumentException(sprintf('Invalid option specified: \"%s\". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));\n        }\n\n        $pos = array_search(static::$availableOptions[$option], $this->options);\n        if (false !== $pos) {\n            unset($this->options[$pos]);\n        }\n    }\n\n    /**\n     * 批量设置字体格式\n     * @param array $options\n     */\n    public function setOptions(array $options)\n    {\n        $this->options = [];\n\n        foreach ($options as $option) {\n            $this->setOption($option);\n        }\n    }\n\n    /**\n     * 应用样式到文字\n     * @param string $text 文字\n     * @return string\n     */\n    public function apply($text)\n    {\n        $setCodes   = [];\n        $unsetCodes = [];\n\n        if (null !== $this->foreground) {\n            $setCodes[]   = $this->foreground['set'];\n            $unsetCodes[] = $this->foreground['unset'];\n        }\n        if (null !== $this->background) {\n            $setCodes[]   = $this->background['set'];\n            $unsetCodes[] = $this->background['unset'];\n        }\n        if (count($this->options)) {\n            foreach ($this->options as $option) {\n                $setCodes[]   = $option['set'];\n                $unsetCodes[] = $option['unset'];\n            }\n        }\n\n        if (0 === count($setCodes)) {\n            return $text;\n        }\n\n        return sprintf(\"\\033[%sm%s\\033[%sm\", implode(';', $setCodes), $text, implode(';', $unsetCodes));\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/question/Choice.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output\\question;\n\nuse think\\console\\output\\Question;\n\nclass Choice extends Question\n{\n\n    private $choices;\n    private $multiselect  = false;\n    private $prompt       = ' > ';\n    private $errorMessage = 'Value \"%s\" is invalid';\n\n    /**\n     * 构造方法\n     * @param string $question 问题\n     * @param array  $choices  选项\n     * @param mixed  $default  默认答案\n     */\n    public function __construct($question, array $choices, $default = null)\n    {\n        parent::__construct($question, $default);\n\n        $this->choices = $choices;\n        $this->setValidator($this->getDefaultValidator());\n        $this->setAutocompleterValues($choices);\n    }\n\n    /**\n     * 可选项\n     * @return array\n     */\n    public function getChoices()\n    {\n        return $this->choices;\n    }\n\n    /**\n     * 设置可否多选\n     * @param bool $multiselect\n     * @return self\n     */\n    public function setMultiselect($multiselect)\n    {\n        $this->multiselect = $multiselect;\n        $this->setValidator($this->getDefaultValidator());\n\n        return $this;\n    }\n\n    public function isMultiselect()\n    {\n        return $this->multiselect;\n    }\n\n    /**\n     * 获取提示\n     * @return string\n     */\n    public function getPrompt()\n    {\n        return $this->prompt;\n    }\n\n    /**\n     * 设置提示\n     * @param string $prompt\n     * @return self\n     */\n    public function setPrompt($prompt)\n    {\n        $this->prompt = $prompt;\n\n        return $this;\n    }\n\n    /**\n     * 设置错误提示信息\n     * @param string $errorMessage\n     * @return self\n     */\n    public function setErrorMessage($errorMessage)\n    {\n        $this->errorMessage = $errorMessage;\n        $this->setValidator($this->getDefaultValidator());\n\n        return $this;\n    }\n\n    /**\n     * 获取默认的验证方法\n     * @return callable\n     */\n    private function getDefaultValidator()\n    {\n        $choices      = $this->choices;\n        $errorMessage = $this->errorMessage;\n        $multiselect  = $this->multiselect;\n        $isAssoc      = $this->isAssoc($choices);\n\n        return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {\n            // Collapse all spaces.\n            $selectedChoices = str_replace(' ', '', $selected);\n\n            if ($multiselect) {\n                // Check for a separated comma values\n                if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {\n                    throw new \\InvalidArgumentException(sprintf($errorMessage, $selected));\n                }\n                $selectedChoices = explode(',', $selectedChoices);\n            } else {\n                $selectedChoices = [$selected];\n            }\n\n            $multiselectChoices = [];\n            foreach ($selectedChoices as $value) {\n                $results = [];\n                foreach ($choices as $key => $choice) {\n                    if ($choice === $value) {\n                        $results[] = $key;\n                    }\n                }\n\n                if (count($results) > 1) {\n                    throw new \\InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results)));\n                }\n\n                $result = array_search($value, $choices);\n\n                if (!$isAssoc) {\n                    if (!empty($result)) {\n                        $result = $choices[$result];\n                    } elseif (isset($choices[$value])) {\n                        $result = $choices[$value];\n                    }\n                } elseif (empty($result) && array_key_exists($value, $choices)) {\n                    $result = $value;\n                }\n\n                if (empty($result)) {\n                    throw new \\InvalidArgumentException(sprintf($errorMessage, $value));\n                }\n                array_push($multiselectChoices, $result);\n            }\n\n            if ($multiselect) {\n                return $multiselectChoices;\n            }\n\n            return current($multiselectChoices);\n        };\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/console/output/question/Confirmation.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\console\\output\\question;\n\nuse think\\console\\output\\Question;\n\nclass Confirmation extends Question\n{\n\n    private $trueAnswerRegex;\n\n    /**\n     * 构造方法\n     * @param string $question        问题\n     * @param bool   $default         默认答案\n     * @param string $trueAnswerRegex 验证正则\n     */\n    public function __construct($question, $default = true, $trueAnswerRegex = '/^y/i')\n    {\n        parent::__construct($question, (bool) $default);\n\n        $this->trueAnswerRegex = $trueAnswerRegex;\n        $this->setNormalizer($this->getDefaultNormalizer());\n    }\n\n    /**\n     * 获取默认的答案回调\n     * @return callable\n     */\n    private function getDefaultNormalizer()\n    {\n        $default = $this->getDefault();\n        $regex   = $this->trueAnswerRegex;\n\n        return function ($answer) use ($default, $regex) {\n            if (is_bool($answer)) {\n                return $answer;\n            }\n\n            $answerIsTrue = (bool) preg_match($regex, $answer);\n            if (false === $default) {\n                return $answer && $answerIsTrue;\n            }\n\n            return !$answer || $answerIsTrue;\n        };\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/controller/Rest.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\controller;\n\nuse think\\App;\nuse think\\Request;\nuse think\\Response;\n\nabstract class Rest\n{\n\n    protected $method; // 当前请求类型\n    protected $type; // 当前资源类型\n    // 输出类型\n    protected $restMethodList    = 'get|post|put|delete';\n    protected $restDefaultMethod = 'get';\n    protected $restTypeList      = 'html|xml|json|rss';\n    protected $restDefaultType   = 'html';\n    protected $restOutputType    = [ // REST允许输出的资源类型列表\n        'xml'  => 'application/xml',\n        'json' => 'application/json',\n        'html' => 'text/html',\n    ];\n\n    /**\n     * 构造函数 取得模板对象实例\n     * @access public\n     */\n    public function __construct()\n    {\n        // 资源类型检测\n        $request = Request::instance();\n        $ext     = $request->ext();\n        if ('' == $ext) {\n            // 自动检测资源类型\n            $this->type = $request->type();\n        } elseif (!preg_match('/\\(' . $this->restTypeList . '\\)$/i', $ext)) {\n            // 资源类型非法 则用默认资源类型访问\n            $this->type = $this->restDefaultType;\n        } else {\n            $this->type = $ext;\n        }\n        // 请求方式检测\n        $method = strtolower($request->method());\n        if (false === stripos($this->restMethodList, $method)) {\n            // 请求方式非法 则用默认请求方法\n            $method = $this->restDefaultMethod;\n        }\n        $this->method = $method;\n    }\n\n    /**\n     * REST 调用\n     * @access public\n     * @param string $method 方法名\n     * @return mixed\n     * @throws \\Exception\n     */\n    public function _empty($method)\n    {\n        if (method_exists($this, $method . '_' . $this->method . '_' . $this->type)) {\n            // RESTFul方法支持\n            $fun = $method . '_' . $this->method . '_' . $this->type;\n        } elseif ($this->method == $this->restDefaultMethod && method_exists($this, $method . '_' . $this->type)) {\n            $fun = $method . '_' . $this->type;\n        } elseif ($this->type == $this->restDefaultType && method_exists($this, $method . '_' . $this->method)) {\n            $fun = $method . '_' . $this->method;\n        }\n        if (isset($fun)) {\n            return App::invokeMethod([$this, $fun]);\n        } else {\n            // 抛出异常\n            throw new \\Exception('error action :' . $method);\n        }\n    }\n\n    /**\n     * 输出返回数据\n     * @access protected\n     * @param mixed     $data 要返回的数据\n     * @param String    $type 返回类型 JSON XML\n     * @param integer   $code HTTP状态码\n     * @return Response\n     */\n    protected function response($data, $type = 'json', $code = 200)\n    {\n        return Response::create($data, $type)->code($code);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/controller/Yar.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\controller;\n\n/**\n * ThinkPHP Yar控制器类\n */\nabstract class Yar\n{\n\n    /**\n     * 构造函数\n     * @access public\n     */\n    public function __construct()\n    {\n        //控制器初始化\n        if (method_exists($this, '_initialize')) {\n            $this->_initialize();\n        }\n\n        //判断扩展是否存在\n        if (!extension_loaded('yar')) {\n            throw new \\Exception('not support yar');\n        }\n\n        //实例化Yar_Server\n        $server = new \\Yar_Server($this);\n        // 启动server\n        $server->handle();\n    }\n\n    /**\n     * 魔术方法 有不存在的操作的时候执行\n     * @access public\n     * @param string $method 方法名\n     * @param array $args 参数\n     * @return mixed\n     */\n    public function __call($method, $args)\n    {}\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/Builder.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db;\n\nuse PDO;\nuse think\\Exception;\n\nabstract class Builder\n{\n    // connection对象实例\n    protected $connection;\n    // 查询对象实例\n    protected $query;\n\n    // 数据库表达式\n    protected $exp = ['eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'not like' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'exp' => 'EXP', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN', 'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN', 'exists' => 'EXISTS', 'notexists' => 'NOT EXISTS', 'not exists' => 'NOT EXISTS', 'null' => 'NULL', 'notnull' => 'NOT NULL', 'not null' => 'NOT NULL', '> time' => '> TIME', '< time' => '< TIME', '>= time' => '>= TIME', '<= time' => '<= TIME', 'between time' => 'BETWEEN TIME', 'not between time' => 'NOT BETWEEN TIME', 'notbetween time' => 'NOT BETWEEN TIME'];\n\n    // SQL表达式\n    protected $selectSql    = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%';\n    protected $insertSql    = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';\n    protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';\n    protected $updateSql    = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';\n    protected $deleteSql    = 'DELETE FROM %TABLE% %USING% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';\n\n    /**\n     * 构造函数\n     * @access public\n     * @param Connection    $connection 数据库连接对象实例\n     * @param Query         $query      数据库查询对象实例\n     */\n    public function __construct(Connection $connection, Query $query)\n    {\n        $this->connection = $connection;\n        $this->query      = $query;\n    }\n\n    /**\n     * 获取当前的连接对象实例\n     * @access public\n     * @return void\n     */\n    public function getConnection()\n    {\n        return $this->connection;\n    }\n\n    /**\n     * 获取当前的Query对象实例\n     * @access public\n     * @return void\n     */\n    public function getQuery()\n    {\n        return $this->query;\n    }\n\n    /**\n     * 将SQL语句中的__TABLE_NAME__字符串替换成带前缀的表名（小写）\n     * @access protected\n     * @param string $sql sql语句\n     * @return string\n     */\n    protected function parseSqlTable($sql)\n    {\n        return $this->query->parseSqlTable($sql);\n    }\n\n    /**\n     * 数据分析\n     * @access protected\n     * @param array     $data 数据\n     * @param array     $options 查询参数\n     * @return array\n     */\n    protected function parseData($data, $options)\n    {\n        if (empty($data)) {\n            return [];\n        }\n\n        // 获取绑定信息\n        $bind = $this->query->getFieldsBind($options['table']);\n        if ('*' == $options['field']) {\n            $fields = array_keys($bind);\n        } else {\n            $fields = $options['field'];\n        }\n\n        $result = [];\n        foreach ($data as $key => $val) {\n            $item = $this->parseKey($key, $options);\n            if (is_object($val) && method_exists($val, '__toString')) {\n                // 对象数据写入\n                $val = $val->__toString();\n            }\n            if (false === strpos($key, '.') && !in_array($key, $fields, true)) {\n                if ($options['strict']) {\n                    throw new Exception('fields not exists:[' . $key . ']');\n                }\n            } elseif (is_null($val)) {\n                $result[$item] = 'NULL';\n            } elseif (isset($val[0]) && 'exp' == $val[0]) {\n                $result[$item] = $val[1];\n            } elseif (is_scalar($val)) {\n                // 过滤非标量数据\n                if (0 === strpos($val, ':') && $this->query->isBind(substr($val, 1))) {\n                    $result[$item] = $val;\n                } else {\n                    $key = str_replace('.', '_', $key);\n                    $this->query->bind('__data__' . $key, $val, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR);\n                    $result[$item] = ':__data__' . $key;\n                }\n            }\n        }\n        return $result;\n    }\n\n    /**\n     * 字段名分析\n     * @access protected\n     * @param string $key\n     * @param array  $options\n     * @return string\n     */\n    protected function parseKey($key, $options = [])\n    {\n        return $key;\n    }\n\n    /**\n     * value分析\n     * @access protected\n     * @param mixed     $value\n     * @param string    $field\n     * @return string|array\n     */\n    protected function parseValue($value, $field = '')\n    {\n        if (is_string($value)) {\n            $value = strpos($value, ':') === 0 && $this->query->isBind(substr($value, 1)) ? $value : $this->connection->quote($value);\n        } elseif (is_array($value)) {\n            $value = array_map([$this, 'parseValue'], $value);\n        } elseif (is_bool($value)) {\n            $value = $value ? '1' : '0';\n        } elseif (is_null($value)) {\n            $value = 'null';\n        }\n        return $value;\n    }\n\n    /**\n     * field分析\n     * @access protected\n     * @param mixed     $fields\n     * @param array     $options\n     * @return string\n     */\n    protected function parseField($fields, $options = [])\n    {\n        if ('*' == $fields || empty($fields)) {\n            $fieldsStr = '*';\n        } elseif (is_array($fields)) {\n            // 支持 'field1'=>'field2' 这样的字段别名定义\n            $array = [];\n            foreach ($fields as $key => $field) {\n                if (!is_numeric($key)) {\n                    $array[] = $this->parseKey($key, $options) . ' AS ' . $this->parseKey($field, $options);\n                } else {\n                    $array[] = $this->parseKey($field, $options);\n                }\n            }\n            $fieldsStr = implode(',', $array);\n        }\n        return $fieldsStr;\n    }\n\n    /**\n     * table分析\n     * @access protected\n     * @param mixed $tables\n     * @param array $options\n     * @return string\n     */\n    protected function parseTable($tables, $options = [])\n    {\n        $item = [];\n        foreach ((array) $tables as $key => $table) {\n            if (!is_numeric($key)) {\n                if (strpos($key, '@think')) {\n                    $key = strstr($key, '@think', true);\n                }\n                $key    = $this->parseSqlTable($key);\n                $item[] = $this->parseKey($key) . ' ' . (isset($options['alias'][$table]) ? $this->parseKey($options['alias'][$table]) : $this->parseKey($table));\n            } else {\n                $table = $this->parseSqlTable($table);\n                if (isset($options['alias'][$table])) {\n                    $item[] = $this->parseKey($table) . ' ' . $this->parseKey($options['alias'][$table]);\n                } else {\n                    $item[] = $this->parseKey($table);\n                }\n            }\n        }\n        return implode(',', $item);\n    }\n\n    /**\n     * where分析\n     * @access protected\n     * @param mixed $where   查询条件\n     * @param array $options 查询参数\n     * @return string\n     */\n    protected function parseWhere($where, $options)\n    {\n        $whereStr = $this->buildWhere($where, $options);\n        if (!empty($options['soft_delete'])) {\n            // 附加软删除条件\n            list($field, $condition) = $options['soft_delete'];\n\n            $binds    = $this->query->getFieldsBind($options['table']);\n            $whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : '';\n            $whereStr = $whereStr . $this->parseWhereItem($field, $condition, '', $options, $binds);\n        }\n        return empty($whereStr) ? '' : ' WHERE ' . $whereStr;\n    }\n\n    /**\n     * 生成查询条件SQL\n     * @access public\n     * @param mixed     $where\n     * @param array     $options\n     * @return string\n     */\n    public function buildWhere($where, $options)\n    {\n        if (empty($where)) {\n            $where = [];\n        }\n\n        if ($where instanceof Query) {\n            return $this->buildWhere($where->getOptions('where'), $options);\n        }\n\n        $whereStr = '';\n        $binds    = $this->query->getFieldsBind($options['table']);\n        foreach ($where as $key => $val) {\n            $str = [];\n            foreach ($val as $field => $value) {\n                if ($value instanceof \\Closure) {\n                    // 使用闭包查询\n                    $query = new Query($this->connection);\n                    call_user_func_array($value, [ & $query]);\n                    $whereClause = $this->buildWhere($query->getOptions('where'), $options);\n                    if (!empty($whereClause)) {\n                        $str[] = ' ' . $key . ' ( ' . $whereClause . ' )';\n                    }\n                } elseif (strpos($field, '|')) {\n                    // 不同字段使用相同查询条件（OR）\n                    $array = explode('|', $field);\n                    $item  = [];\n                    foreach ($array as $k) {\n                        $item[] = $this->parseWhereItem($k, $value, '', $options, $binds);\n                    }\n                    $str[] = ' ' . $key . ' ( ' . implode(' OR ', $item) . ' )';\n                } elseif (strpos($field, '&')) {\n                    // 不同字段使用相同查询条件（AND）\n                    $array = explode('&', $field);\n                    $item  = [];\n                    foreach ($array as $k) {\n                        $item[] = $this->parseWhereItem($k, $value, '', $options, $binds);\n                    }\n                    $str[] = ' ' . $key . ' ( ' . implode(' AND ', $item) . ' )';\n                } else {\n                    // 对字段使用表达式查询\n                    $field = is_string($field) ? $field : '';\n                    $str[] = ' ' . $key . ' ' . $this->parseWhereItem($field, $value, $key, $options, $binds);\n                }\n            }\n\n            $whereStr .= empty($whereStr) ? substr(implode(' ', $str), strlen($key) + 1) : implode(' ', $str);\n        }\n\n        return $whereStr;\n    }\n\n    // where子单元分析\n    protected function parseWhereItem($field, $val, $rule = '', $options = [], $binds = [], $bindName = null)\n    {\n        // 字段分析\n        $key = $field ? $this->parseKey($field, $options) : '';\n\n        // 查询规则和条件\n        if (!is_array($val)) {\n            $val = ['=', $val];\n        }\n        list($exp, $value) = $val;\n\n        // 对一个字段使用多个查询条件\n        if (is_array($exp)) {\n            $item = array_pop($val);\n            // 传入 or 或者 and\n            if (is_string($item) && in_array($item, ['AND', 'and', 'OR', 'or'])) {\n                $rule = $item;\n            } else {\n                array_push($val, $item);\n            }\n            foreach ($val as $k => $item) {\n                $bindName = 'where_' . str_replace('.', '_', $field) . '_' . $k;\n                $str[]    = $this->parseWhereItem($field, $item, $rule, $options, $binds, $bindName);\n            }\n            return '( ' . implode(' ' . $rule . ' ', $str) . ' )';\n        }\n\n        // 检测操作符\n        if (!in_array($exp, $this->exp)) {\n            $exp = strtolower($exp);\n            if (isset($this->exp[$exp])) {\n                $exp = $this->exp[$exp];\n            } else {\n                throw new Exception('where express error:' . $exp);\n            }\n        }\n        $bindName = $bindName ?: 'where_' . str_replace(['.', '-'], '_', $field);\n        if (preg_match('/\\W/', $bindName)) {\n            // 处理带非单词字符的字段名\n            $bindName = md5($bindName);\n        }\n\n        $bindType = isset($binds[$field]) ? $binds[$field] : PDO::PARAM_STR;\n        if (is_scalar($value) && array_key_exists($field, $binds) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) {\n            if (strpos($value, ':') !== 0 || !$this->query->isBind(substr($value, 1))) {\n                if ($this->query->isBind($bindName)) {\n                    $bindName .= '_' . str_replace('.', '_', uniqid('', true));\n                }\n                $this->query->bind($bindName, $value, $bindType);\n                $value = ':' . $bindName;\n            }\n        }\n\n        $whereStr = '';\n        if (in_array($exp, ['=', '<>', '>', '>=', '<', '<='])) {\n            // 比较运算\n            if ($value instanceof \\Closure) {\n                $whereStr .= $key . ' ' . $exp . ' ' . $this->parseClosure($value);\n            } else {\n                $whereStr .= $key . ' ' . $exp . ' ' . $this->parseValue($value, $field);\n            }\n        } elseif ('LIKE' == $exp || 'NOT LIKE' == $exp) {\n            // 模糊匹配\n            if (is_array($value)) {\n                foreach ($value as $item) {\n                    $array[] = $key . ' ' . $exp . ' ' . $this->parseValue($item, $field);\n                }\n                $logic = isset($val[2]) ? $val[2] : 'AND';\n                $whereStr .= '(' . implode($array, ' ' . strtoupper($logic) . ' ') . ')';\n            } else {\n                $whereStr .= $key . ' ' . $exp . ' ' . $this->parseValue($value, $field);\n            }\n        } elseif ('EXP' == $exp) {\n            // 表达式查询\n            $whereStr .= '( ' . $key . ' ' . $value . ' )';\n        } elseif (in_array($exp, ['NOT NULL', 'NULL'])) {\n            // NULL 查询\n            $whereStr .= $key . ' IS ' . $exp;\n        } elseif (in_array($exp, ['NOT IN', 'IN'])) {\n            // IN 查询\n            if ($value instanceof \\Closure) {\n                $whereStr .= $key . ' ' . $exp . ' ' . $this->parseClosure($value);\n            } else {\n                $value = array_unique(is_array($value) ? $value : explode(',', $value));\n                if (array_key_exists($field, $binds)) {\n                    $bind  = [];\n                    $array = [];\n                    $i     = 0;\n                    foreach ($value as $v) {\n                        $i++;\n                        if ($this->query->isBind($bindName . '_in_' . $i)) {\n                            $bindKey = $bindName . '_in_' . uniqid() . '_' . $i;\n                        } else {\n                            $bindKey = $bindName . '_in_' . $i;\n                        }\n                        $bind[$bindKey] = [$v, $bindType];\n                        $array[]        = ':' . $bindKey;\n                    }\n                    $this->query->bind($bind);\n                    $zone = implode(',', $array);\n                } else {\n                    $zone = implode(',', $this->parseValue($value, $field));\n                }\n                $whereStr .= $key . ' ' . $exp . ' (' . (empty($zone) ? \"''\" : $zone) . ')';\n            }\n        } elseif (in_array($exp, ['NOT BETWEEN', 'BETWEEN'])) {\n            // BETWEEN 查询\n            $data = is_array($value) ? $value : explode(',', $value);\n            if (array_key_exists($field, $binds)) {\n                if ($this->query->isBind($bindName . '_between_1')) {\n                    $bindKey1 = $bindName . '_between_1' . uniqid();\n                    $bindKey2 = $bindName . '_between_2' . uniqid();\n                } else {\n                    $bindKey1 = $bindName . '_between_1';\n                    $bindKey2 = $bindName . '_between_2';\n                }\n                $bind = [\n                    $bindKey1 => [$data[0], $bindType],\n                    $bindKey2 => [$data[1], $bindType],\n                ];\n                $this->query->bind($bind);\n                $between = ':' . $bindKey1 . ' AND :' . $bindKey2;\n            } else {\n                $between = $this->parseValue($data[0], $field) . ' AND ' . $this->parseValue($data[1], $field);\n            }\n            $whereStr .= $key . ' ' . $exp . ' ' . $between;\n        } elseif (in_array($exp, ['NOT EXISTS', 'EXISTS'])) {\n            // EXISTS 查询\n            if ($value instanceof \\Closure) {\n                $whereStr .= $exp . ' ' . $this->parseClosure($value);\n            } else {\n                $whereStr .= $exp . ' (' . $value . ')';\n            }\n        } elseif (in_array($exp, ['< TIME', '> TIME', '<= TIME', '>= TIME'])) {\n            $whereStr .= $key . ' ' . substr($exp, 0, 2) . ' ' . $this->parseDateTime($value, $field, $options, $bindName, $bindType);\n        } elseif (in_array($exp, ['BETWEEN TIME', 'NOT BETWEEN TIME'])) {\n            if (is_string($value)) {\n                $value = explode(',', $value);\n            }\n\n            $whereStr .= $key . ' ' . substr($exp, 0, -4) . $this->parseDateTime($value[0], $field, $options, $bindName . '_between_1', $bindType) . ' AND ' . $this->parseDateTime($value[1], $field, $options, $bindName . '_between_2', $bindType);\n        }\n        return $whereStr;\n    }\n\n    // 执行闭包子查询\n    protected function parseClosure($call, $show = true)\n    {\n        $query = new Query($this->connection);\n        call_user_func_array($call, [ & $query]);\n        return $query->buildSql($show);\n    }\n\n    /**\n     * 日期时间条件解析\n     * @access protected\n     * @param string    $value\n     * @param string    $key\n     * @param array     $options\n     * @param string    $bindName\n     * @param integer   $bindType\n     * @return string\n     */\n    protected function parseDateTime($value, $key, $options = [], $bindName = null, $bindType = null)\n    {\n        // 获取时间字段类型\n        if (strpos($key, '.')) {\n            list($table, $key) = explode('.', $key);\n            if (isset($options['alias']) && $pos = array_search($table, $options['alias'])) {\n                $table = $pos;\n            }\n        } else {\n            $table = $options['table'];\n        }\n        $type = $this->query->getTableInfo($table, 'type');\n        if (isset($type[$key])) {\n            $info = $type[$key];\n        }\n        if (isset($info)) {\n            if (is_string($value)) {\n                $value = strtotime($value) ?: $value;\n            }\n\n            if (preg_match('/(datetime|timestamp)/is', $info)) {\n                // 日期及时间戳类型\n                $value = date('Y-m-d H:i:s', $value);\n            } elseif (preg_match('/(date)/is', $info)) {\n                // 日期及时间戳类型\n                $value = date('Y-m-d', $value);\n            }\n        }\n        $bindName = $bindName ?: $key;\n        $this->query->bind($bindName, $value, $bindType);\n        return ':' . $bindName;\n    }\n\n    /**\n     * limit分析\n     * @access protected\n     * @param mixed $lmit\n     * @return string\n     */\n    protected function parseLimit($limit)\n    {\n        return (!empty($limit) && false === strpos($limit, '(')) ? ' LIMIT ' . $limit . ' ' : '';\n    }\n\n    /**\n     * join分析\n     * @access protected\n     * @param array $join\n     * @param array $options 查询条件\n     * @return string\n     */\n    protected function parseJoin($join, $options = [])\n    {\n        $joinStr = '';\n        if (!empty($join)) {\n            foreach ($join as $item) {\n                list($table, $type, $on) = $item;\n                $condition               = [];\n                foreach ((array) $on as $val) {\n                    if (strpos($val, '=')) {\n                        list($val1, $val2) = explode('=', $val, 2);\n                        $condition[]       = $this->parseKey($val1, $options) . '=' . $this->parseKey($val2, $options);\n                    } else {\n                        $condition[] = $val;\n                    }\n                }\n\n                $table = $this->parseTable($table, $options);\n                $joinStr .= ' ' . $type . ' JOIN ' . $table . ' ON ' . implode(' AND ', $condition);\n            }\n        }\n        return $joinStr;\n    }\n\n    /**\n     * order分析\n     * @access protected\n     * @param mixed $order\n     * @param array $options 查询条件\n     * @return string\n     */\n    protected function parseOrder($order, $options = [])\n    {\n        if (is_array($order)) {\n            $array = [];\n            foreach ($order as $key => $val) {\n                if (is_numeric($key)) {\n                    if ('[rand]' == $val) {\n                        $array[] = $this->parseRand();\n                    } elseif (false === strpos($val, '(')) {\n                        $array[] = $this->parseKey($val, $options);\n                    } else {\n                        $array[] = $val;\n                    }\n                } else {\n                    $sort    = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : '';\n                    $array[] = $this->parseKey($key, $options) . ' ' . $sort;\n                }\n            }\n            $order = implode(',', $array);\n        }\n        return !empty($order) ? ' ORDER BY ' . $order : '';\n    }\n\n    /**\n     * group分析\n     * @access protected\n     * @param mixed $group\n     * @return string\n     */\n    protected function parseGroup($group)\n    {\n        return !empty($group) ? ' GROUP BY ' . $group : '';\n    }\n\n    /**\n     * having分析\n     * @access protected\n     * @param string $having\n     * @return string\n     */\n    protected function parseHaving($having)\n    {\n        return !empty($having) ? ' HAVING ' . $having : '';\n    }\n\n    /**\n     * comment分析\n     * @access protected\n     * @param string $comment\n     * @return string\n     */\n    protected function parseComment($comment)\n    {\n        return !empty($comment) ? ' /* ' . $comment . ' */' : '';\n    }\n\n    /**\n     * distinct分析\n     * @access protected\n     * @param mixed $distinct\n     * @return string\n     */\n    protected function parseDistinct($distinct)\n    {\n        return !empty($distinct) ? ' DISTINCT ' : '';\n    }\n\n    /**\n     * union分析\n     * @access protected\n     * @param mixed $union\n     * @return string\n     */\n    protected function parseUnion($union)\n    {\n        if (empty($union)) {\n            return '';\n        }\n        $type = $union['type'];\n        unset($union['type']);\n        foreach ($union as $u) {\n            if ($u instanceof \\Closure) {\n                $sql[] = $type . ' ' . $this->parseClosure($u, false);\n            } elseif (is_string($u)) {\n                $sql[] = $type . ' ' . $this->parseSqlTable($u);\n            }\n        }\n        return implode(' ', $sql);\n    }\n\n    /**\n     * index分析，可在操作链中指定需要强制使用的索引\n     * @access protected\n     * @param mixed $index\n     * @return string\n     */\n    protected function parseForce($index)\n    {\n        if (empty($index)) {\n            return '';\n        }\n\n        if (is_array($index)) {\n            $index = join(\",\", $index);\n        }\n\n        return sprintf(\" FORCE INDEX ( %s ) \", $index);\n    }\n\n    /**\n     * 设置锁机制\n     * @access protected\n     * @param bool $locl\n     * @return string\n     */\n    protected function parseLock($lock = false)\n    {\n        return $lock ? ' FOR UPDATE ' : '';\n    }\n\n    /**\n     * 生成查询SQL\n     * @access public\n     * @param array $options 表达式\n     * @return string\n     */\n    public function select($options = [])\n    {\n        $sql = str_replace(\n            ['%TABLE%', '%DISTINCT%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'],\n            [\n                $this->parseTable($options['table'], $options),\n                $this->parseDistinct($options['distinct']),\n                $this->parseField($options['field'], $options),\n                $this->parseJoin($options['join'], $options),\n                $this->parseWhere($options['where'], $options),\n                $this->parseGroup($options['group']),\n                $this->parseHaving($options['having']),\n                $this->parseOrder($options['order'], $options),\n                $this->parseLimit($options['limit']),\n                $this->parseUnion($options['union']),\n                $this->parseLock($options['lock']),\n                $this->parseComment($options['comment']),\n                $this->parseForce($options['force']),\n            ], $this->selectSql);\n        return $sql;\n    }\n\n    /**\n     * 生成insert SQL\n     * @access public\n     * @param array     $data 数据\n     * @param array     $options 表达式\n     * @param bool      $replace 是否replace\n     * @return string\n     */\n    public function insert(array $data, $options = [], $replace = false)\n    {\n        // 分析并处理数据\n        $data = $this->parseData($data, $options);\n        if (empty($data)) {\n            return 0;\n        }\n        $fields = array_keys($data);\n        $values = array_values($data);\n\n        $sql = str_replace(\n            ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],\n            [\n                $replace ? 'REPLACE' : 'INSERT',\n                $this->parseTable($options['table'], $options),\n                implode(' , ', $fields),\n                implode(' , ', $values),\n                $this->parseComment($options['comment']),\n            ], $this->insertSql);\n\n        return $sql;\n    }\n\n    /**\n     * 生成insertall SQL\n     * @access public\n     * @param array     $dataSet 数据集\n     * @param array     $options 表达式\n     * @param bool      $replace 是否replace\n     * @return string\n     */\n    public function insertAll($dataSet, $options, $replace = false)\n    {\n        // 获取合法的字段\n        if ('*' == $options['field']) {\n            $fields = array_keys($this->query->getFieldsType($options['table']));\n        } else {\n            $fields = $options['field'];\n        }\n\n        foreach ($dataSet as &$data) {\n            foreach ($data as $key => $val) {\n                if (!in_array($key, $fields, true)) {\n                    if ($options['strict']) {\n                        throw new Exception('fields not exists:[' . $key . ']');\n                    }\n                    unset($data[$key]);\n                } elseif (is_null($val)) {\n                    $data[$key] = 'NULL';\n                } elseif (is_scalar($val)) {\n                    $data[$key] = $this->parseValue($val, $key);\n                } elseif (is_object($val) && method_exists($val, '__toString')) {\n                    // 对象数据写入\n                    $data[$key] = $val->__toString();\n                } else {\n                    // 过滤掉非标量数据\n                    unset($data[$key]);\n                }\n            }\n            $value    = array_values($data);\n            $values[] = 'SELECT ' . implode(',', $value);\n        }\n        $fields = array_map([$this, 'parseKey'], array_keys(reset($dataSet)));\n        $sql    = str_replace(\n            ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],\n            [\n                $replace ? 'REPLACE' : 'INSERT',\n                $this->parseTable($options['table'], $options),\n                implode(' , ', $fields),\n                implode(' UNION ALL ', $values),\n                $this->parseComment($options['comment']),\n            ], $this->insertAllSql);\n\n        return $sql;\n    }\n\n    /**\n     * 生成slectinsert SQL\n     * @access public\n     * @param array     $fields 数据\n     * @param string    $table 数据表\n     * @param array     $options 表达式\n     * @return string\n     */\n    public function selectInsert($fields, $table, $options)\n    {\n        if (is_string($fields)) {\n            $fields = explode(',', $fields);\n        }\n\n        $fields = array_map([$this, 'parseKey'], $fields);\n        $sql    = 'INSERT INTO ' . $this->parseTable($table, $options) . ' (' . implode(',', $fields) . ') ' . $this->select($options);\n        return $sql;\n    }\n\n    /**\n     * 生成update SQL\n     * @access public\n     * @param array     $fields 数据\n     * @param array     $options 表达式\n     * @return string\n     */\n    public function update($data, $options)\n    {\n        $table = $this->parseTable($options['table'], $options);\n        $data  = $this->parseData($data, $options);\n        if (empty($data)) {\n            return '';\n        }\n        foreach ($data as $key => $val) {\n            $set[] = $key . '=' . $val;\n        }\n\n        $sql = str_replace(\n            ['%TABLE%', '%SET%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],\n            [\n                $this->parseTable($options['table'], $options),\n                implode(',', $set),\n                $this->parseJoin($options['join'], $options),\n                $this->parseWhere($options['where'], $options),\n                $this->parseOrder($options['order'], $options),\n                $this->parseLimit($options['limit']),\n                $this->parseLock($options['lock']),\n                $this->parseComment($options['comment']),\n            ], $this->updateSql);\n\n        return $sql;\n    }\n\n    /**\n     * 生成delete SQL\n     * @access public\n     * @param array $options 表达式\n     * @return string\n     */\n    public function delete($options)\n    {\n        $sql = str_replace(\n            ['%TABLE%', '%USING%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'],\n            [\n                $this->parseTable($options['table'], $options),\n                !empty($options['using']) ? ' USING ' . $this->parseTable($options['using'], $options) . ' ' : '',\n                $this->parseJoin($options['join'], $options),\n                $this->parseWhere($options['where'], $options),\n                $this->parseOrder($options['order'], $options),\n                $this->parseLimit($options['limit']),\n                $this->parseLock($options['lock']),\n                $this->parseComment($options['comment']),\n            ], $this->deleteSql);\n\n        return $sql;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/Connection.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db;\n\nuse PDO;\nuse PDOStatement;\nuse think\\Db;\nuse think\\db\\exception\\BindParamException;\nuse think\\Debug;\nuse think\\Exception;\nuse think\\exception\\PDOException;\nuse think\\Log;\n\n/**\n * Class Connection\n * @package think\n * @method Query table(string $table) 指定数据表（含前缀）\n * @method Query name(string $name) 指定数据表（不含前缀）\n *\n */\nabstract class Connection\n{\n\n    /** @var PDOStatement PDO操作实例 */\n    protected $PDOStatement;\n\n    /** @var string 当前SQL指令 */\n    protected $queryStr = '';\n    // 返回或者影响记录数\n    protected $numRows = 0;\n    // 事务指令数\n    protected $transTimes = 0;\n    // 错误信息\n    protected $error = '';\n\n    /** @var PDO[] 数据库连接ID 支持多个连接 */\n    protected $links = [];\n\n    /** @var PDO 当前连接ID */\n    protected $linkID;\n    protected $linkRead;\n    protected $linkWrite;\n\n    // 查询结果类型\n    protected $fetchType = PDO::FETCH_ASSOC;\n    // 字段属性大小写\n    protected $attrCase = PDO::CASE_LOWER;\n    // 监听回调\n    protected static $event = [];\n    // 使用Builder类\n    protected $builder;\n    // 数据库连接参数配置\n    protected $config = [\n        // 数据库类型\n        'type'            => '',\n        // 服务器地址\n        'hostname'        => '',\n        // 数据库名\n        'database'        => '',\n        // 用户名\n        'username'        => '',\n        // 密码\n        'password'        => '',\n        // 端口\n        'hostport'        => '',\n        // 连接dsn\n        'dsn'             => '',\n        // 数据库连接参数\n        'params'          => [],\n        // 数据库编码默认采用utf8\n        'charset'         => 'utf8',\n        // 数据库表前缀\n        'prefix'          => '',\n        // 数据库调试模式\n        'debug'           => false,\n        // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)\n        'deploy'          => 0,\n        // 数据库读写是否分离 主从式有效\n        'rw_separate'     => false,\n        // 读写分离后 主服务器数量\n        'master_num'      => 1,\n        // 指定从服务器序号\n        'slave_no'        => '',\n        // 是否严格检查字段是否存在\n        'fields_strict'   => true,\n        // 数据返回类型\n        'result_type'     => PDO::FETCH_ASSOC,\n        // 数据集返回类型\n        'resultset_type'  => 'array',\n        // 自动写入时间戳字段\n        'auto_timestamp'  => false,\n        // 时间字段取出后的默认时间格式\n        'datetime_format' => 'Y-m-d H:i:s',\n        // 是否需要进行SQL性能分析\n        'sql_explain'     => false,\n        // Builder类\n        'builder'         => '',\n        // Query类\n        'query'           => '\\\\think\\\\db\\\\Query',\n        // 是否需要断线重连\n        'break_reconnect' => false,\n    ];\n\n    // PDO连接参数\n    protected $params = [\n        PDO::ATTR_CASE              => PDO::CASE_NATURAL,\n        PDO::ATTR_ERRMODE           => PDO::ERRMODE_EXCEPTION,\n        PDO::ATTR_ORACLE_NULLS      => PDO::NULL_NATURAL,\n        PDO::ATTR_STRINGIFY_FETCHES => false,\n        PDO::ATTR_EMULATE_PREPARES  => false,\n    ];\n\n    // 绑定参数\n    protected $bind = [];\n\n    /**\n     * 构造函数 读取数据库配置信息\n     * @access public\n     * @param array $config 数据库配置数组\n     */\n    public function __construct(array $config = [])\n    {\n        if (!empty($config)) {\n            $this->config = array_merge($this->config, $config);\n        }\n    }\n\n    /**\n     * 获取新的查询对象\n     * @access protected\n     * @return Query\n     */\n    protected function getQuery()\n    {\n        $class = $this->config['query'];\n        return new $class($this);\n    }\n\n    /**\n     * 获取当前连接器类对应的Builder类\n     * @access public\n     * @return string\n     */\n    public function getBuilder()\n    {\n        if (!empty($this->builder)) {\n            return $this->builder;\n        } else {\n            return $this->getConfig('builder') ?: '\\\\think\\\\db\\\\builder\\\\' . ucfirst($this->getConfig('type'));\n        }\n    }\n\n    /**\n     * 调用Query类的查询方法\n     * @access public\n     * @param string    $method 方法名称\n     * @param array     $args 调用参数\n     * @return mixed\n     */\n    public function __call($method, $args)\n    {\n        return call_user_func_array([$this->getQuery(), $method], $args);\n    }\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access protected\n     * @param array $config 连接信息\n     * @return string\n     */\n    abstract protected function parseDsn($config);\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @param string $tableName\n     * @return array\n     */\n    abstract public function getFields($tableName);\n\n    /**\n     * 取得数据库的表信息\n     * @access public\n     * @param string $dbName\n     * @return array\n     */\n    abstract public function getTables($dbName);\n\n    /**\n     * SQL性能分析\n     * @access protected\n     * @param string $sql\n     * @return array\n     */\n    abstract protected function getExplain($sql);\n\n    /**\n     * 对返数据表字段信息进行大小写转换出来\n     * @access public\n     * @param array $info 字段信息\n     * @return array\n     */\n    public function fieldCase($info)\n    {\n        // 字段大小写转换\n        switch ($this->attrCase) {\n            case PDO::CASE_LOWER:\n                $info = array_change_key_case($info);\n                break;\n            case PDO::CASE_UPPER:\n                $info = array_change_key_case($info, CASE_UPPER);\n                break;\n            case PDO::CASE_NATURAL:\n            default:\n                // 不做转换\n        }\n        return $info;\n    }\n\n    /**\n     * 获取数据库的配置参数\n     * @access public\n     * @param string $config 配置名称\n     * @return mixed\n     */\n    public function getConfig($config = '')\n    {\n        return $config ? $this->config[$config] : $this->config;\n    }\n\n    /**\n     * 设置数据库的配置参数\n     * @access public\n     * @param string|array      $config 配置名称\n     * @param mixed             $value 配置值\n     * @return void\n     */\n    public function setConfig($config, $value = '')\n    {\n        if (is_array($config)) {\n            $this->config = array_merge($this->config, $config);\n        } else {\n            $this->config[$config] = $value;\n        }\n    }\n\n    /**\n     * 连接数据库方法\n     * @access public\n     * @param array         $config 连接参数\n     * @param integer       $linkNum 连接序号\n     * @param array|bool    $autoConnection 是否自动连接主数据库（用于分布式）\n     * @return PDO\n     * @throws Exception\n     */\n    public function connect(array $config = [], $linkNum = 0, $autoConnection = false)\n    {\n        if (!isset($this->links[$linkNum])) {\n            if (!$config) {\n                $config = $this->config;\n            } else {\n                $config = array_merge($this->config, $config);\n            }\n            // 连接参数\n            if (isset($config['params']) && is_array($config['params'])) {\n                $params = $config['params'] + $this->params;\n            } else {\n                $params = $this->params;\n            }\n            // 记录当前字段属性大小写设置\n            $this->attrCase = $params[PDO::ATTR_CASE];\n\n            // 数据返回类型\n            if (isset($config['result_type'])) {\n                $this->fetchType = $config['result_type'];\n            }\n            try {\n                if (empty($config['dsn'])) {\n                    $config['dsn'] = $this->parseDsn($config);\n                }\n                if ($config['debug']) {\n                    $startTime = microtime(true);\n                }\n                $this->links[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $params);\n                if ($config['debug']) {\n                    // 记录数据库连接信息\n                    Log::record('[ DB ] CONNECT:[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $config['dsn'], 'sql');\n                }\n            } catch (\\PDOException $e) {\n                if ($autoConnection) {\n                    Log::record($e->getMessage(), 'error');\n                    return $this->connect($autoConnection, $linkNum);\n                } else {\n                    throw $e;\n                }\n            }\n        }\n        return $this->links[$linkNum];\n    }\n\n    /**\n     * 释放查询结果\n     * @access public\n     */\n    public function free()\n    {\n        $this->PDOStatement = null;\n    }\n\n    /**\n     * 获取PDO对象\n     * @access public\n     * @return \\PDO|false\n     */\n    public function getPdo()\n    {\n        if (!$this->linkID) {\n            return false;\n        } else {\n            return $this->linkID;\n        }\n    }\n\n    /**\n     * 执行查询 返回数据集\n     * @access public\n     * @param string        $sql sql指令\n     * @param array         $bind 参数绑定\n     * @param bool          $master 是否在主服务器读操作\n     * @param bool          $pdo 是否返回PDO对象\n     * @return mixed\n     * @throws BindParamException\n     * @throws PDOException\n     */\n    public function query($sql, $bind = [], $master = false, $pdo = false)\n    {\n        $this->initConnect($master);\n        if (!$this->linkID) {\n            return false;\n        }\n\n        // 记录SQL语句\n        $this->queryStr = $sql;\n        if ($bind) {\n            $this->bind = $bind;\n        }\n\n        // 释放前次的查询结果\n        if (!empty($this->PDOStatement)) {\n            $this->free();\n        }\n\n        Db::$queryTimes++;\n        try {\n            // 调试开始\n            $this->debug(true);\n            // 预处理\n            if (empty($this->PDOStatement)) {\n                $this->PDOStatement = $this->linkID->prepare($sql);\n            }\n            // 是否为存储过程调用\n            $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);\n            // 参数绑定\n            if ($procedure) {\n                $this->bindParam($bind);\n            } else {\n                $this->bindValue($bind);\n            }\n            // 执行查询\n            $this->PDOStatement->execute();\n            // 调试结束\n            $this->debug(false);\n            // 返回结果集\n            return $this->getResult($pdo, $procedure);\n        } catch (\\PDOException $e) {\n            if ($this->isBreak($e)) {\n                return $this->close()->query($sql, $bind, $master, $pdo);\n            }\n            throw new PDOException($e, $this->config, $this->getLastsql());\n        } catch (\\Exception $e) {\n            if ($this->isBreak($e)) {\n                return $this->close()->query($sql, $bind, $master, $pdo);\n            }\n            throw $e;\n        }\n    }\n\n    /**\n     * 执行语句\n     * @access public\n     * @param string        $sql sql指令\n     * @param array         $bind 参数绑定\n     * @return int\n     * @throws BindParamException\n     * @throws PDOException\n     */\n    public function execute($sql, $bind = [])\n    {\n        $this->initConnect(true);\n        if (!$this->linkID) {\n            return false;\n        }\n\n        // 记录SQL语句\n        $this->queryStr = $sql;\n        if ($bind) {\n            $this->bind = $bind;\n        }\n\n        //释放前次的查询结果\n        if (!empty($this->PDOStatement) && $this->PDOStatement->queryString != $sql) {\n            $this->free();\n        }\n\n        Db::$executeTimes++;\n        try {\n            // 调试开始\n            $this->debug(true);\n            // 预处理\n            if (empty($this->PDOStatement)) {\n                $this->PDOStatement = $this->linkID->prepare($sql);\n            }\n            // 是否为存储过程调用\n            $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);\n            // 参数绑定\n            if ($procedure) {\n                $this->bindParam($bind);\n            } else {\n                $this->bindValue($bind);\n            }\n            // 执行语句\n            $this->PDOStatement->execute();\n            // 调试结束\n            $this->debug(false);\n\n            $this->numRows = $this->PDOStatement->rowCount();\n            return $this->numRows;\n        } catch (\\PDOException $e) {\n            if ($this->isBreak($e)) {\n                return $this->close()->execute($sql, $bind);\n            }\n            throw new PDOException($e, $this->config, $this->getLastsql());\n        } catch (\\Exception $e) {\n            if ($this->isBreak($e)) {\n                return $this->close()->execute($sql, $bind);\n            }\n            throw $e;\n        }\n    }\n\n    /**\n     * 根据参数绑定组装最终的SQL语句 便于调试\n     * @access public\n     * @param string    $sql 带参数绑定的sql语句\n     * @param array     $bind 参数绑定列表\n     * @return string\n     */\n    public function getRealSql($sql, array $bind = [])\n    {\n        foreach ($bind as $key => $val) {\n            $value = is_array($val) ? $val[0] : $val;\n            $type  = is_array($val) ? $val[1] : PDO::PARAM_STR;\n            if (PDO::PARAM_STR == $type) {\n                $value = $this->quote($value);\n            } elseif (PDO::PARAM_INT == $type) {\n                $value = (float) $value;\n            }\n            // 判断占位符\n            $sql = is_numeric($key) ?\n            substr_replace($sql, $value, strpos($sql, '?'), 1) :\n            str_replace(\n                [':' . $key . ')', ':' . $key . ',', ':' . $key . ' '],\n                [$value . ')', $value . ',', $value . ' '],\n                $sql . ' ');\n        }\n        return rtrim($sql);\n    }\n\n    /**\n     * 参数绑定\n     * 支持 ['name'=>'value','id'=>123] 对应命名占位符\n     * 或者 ['value',123] 对应问号占位符\n     * @access public\n     * @param array $bind 要绑定的参数列表\n     * @return void\n     * @throws BindParamException\n     */\n    protected function bindValue(array $bind = [])\n    {\n        foreach ($bind as $key => $val) {\n            // 占位符\n            $param = is_numeric($key) ? $key + 1 : ':' . $key;\n            if (is_array($val)) {\n                if (PDO::PARAM_INT == $val[1] && '' === $val[0]) {\n                    $val[0] = 0;\n                }\n                $result = $this->PDOStatement->bindValue($param, $val[0], $val[1]);\n            } else {\n                $result = $this->PDOStatement->bindValue($param, $val);\n            }\n            if (!$result) {\n                throw new BindParamException(\n                    \"Error occurred  when binding parameters '{$param}'\",\n                    $this->config,\n                    $this->getLastsql(),\n                    $bind\n                );\n            }\n        }\n    }\n\n    /**\n     * 存储过程的输入输出参数绑定\n     * @access public\n     * @param array $bind 要绑定的参数列表\n     * @return void\n     * @throws BindParamException\n     */\n    protected function bindParam($bind)\n    {\n        foreach ($bind as $key => $val) {\n            $param = is_numeric($key) ? $key + 1 : ':' . $key;\n            if (is_array($val)) {\n                array_unshift($val, $param);\n                $result = call_user_func_array([$this->PDOStatement, 'bindParam'], $val);\n            } else {\n                $result = $this->PDOStatement->bindValue($param, $val);\n            }\n            if (!$result) {\n                $param = array_shift($val);\n                throw new BindParamException(\n                    \"Error occurred  when binding parameters '{$param}'\",\n                    $this->config,\n                    $this->getLastsql(),\n                    $bind\n                );\n            }\n        }\n    }\n\n    /**\n     * 获得数据集数组\n     * @access protected\n     * @param bool   $pdo 是否返回PDOStatement\n     * @param bool   $procedure 是否存储过程\n     * @return array\n     */\n    protected function getResult($pdo = false, $procedure = false)\n    {\n        if ($pdo) {\n            // 返回PDOStatement对象处理\n            return $this->PDOStatement;\n        }\n        if ($procedure) {\n            // 存储过程返回结果\n            return $this->procedure();\n        }\n        $result        = $this->PDOStatement->fetchAll($this->fetchType);\n        $this->numRows = count($result);\n        return $result;\n    }\n\n    /**\n     * 获得存储过程数据集\n     * @access protected\n     * @return array\n     */\n    protected function procedure()\n    {\n        $item = [];\n        do {\n            $result = $this->getResult();\n            if ($result) {\n                $item[] = $result;\n            }\n        } while ($this->PDOStatement->nextRowset());\n        $this->numRows = count($item);\n        return $item;\n    }\n\n    /**\n     * 执行数据库事务\n     * @access public\n     * @param callable $callback 数据操作方法回调\n     * @return mixed\n     * @throws PDOException\n     * @throws \\Exception\n     * @throws \\Throwable\n     */\n    public function transaction($callback)\n    {\n        $this->startTrans();\n        try {\n            $result = null;\n            if (is_callable($callback)) {\n                $result = call_user_func_array($callback, [$this]);\n            }\n            $this->commit();\n            return $result;\n        } catch (\\Exception $e) {\n            $this->rollback();\n            throw $e;\n        } catch (\\Throwable $e) {\n            $this->rollback();\n            throw $e;\n        }\n    }\n\n    /**\n     * 启动事务\n     * @access public\n     * @return void\n     */\n    public function startTrans()\n    {\n        $this->initConnect(true);\n        if (!$this->linkID) {\n            return false;\n        }\n\n        ++$this->transTimes;\n        try {\n            if (1 == $this->transTimes) {\n                $this->linkID->beginTransaction();\n            } elseif ($this->transTimes > 1 && $this->supportSavepoint()) {\n                $this->linkID->exec(\n                    $this->parseSavepoint('trans' . $this->transTimes)\n                );\n            }\n\n        } catch (\\PDOException $e) {\n            if ($this->isBreak($e)) {\n                return $this->close()->startTrans();\n            }\n            throw $e;\n        } catch (\\ErrorException $e) {\n            if ($this->isBreak($e)) {\n                return $this->close()->startTrans();\n            }\n            throw $e;\n        }\n    }\n\n    /**\n     * 用于非自动提交状态下面的查询提交\n     * @access public\n     * @return void\n     * @throws PDOException\n     */\n    public function commit()\n    {\n        $this->initConnect(true);\n\n        if (1 == $this->transTimes) {\n            $this->linkID->commit();\n        }\n\n        --$this->transTimes;\n    }\n\n    /**\n     * 事务回滚\n     * @access public\n     * @return void\n     * @throws PDOException\n     */\n    public function rollback()\n    {\n        $this->initConnect(true);\n\n        if (1 == $this->transTimes) {\n            $this->linkID->rollBack();\n        } elseif ($this->transTimes > 1 && $this->supportSavepoint()) {\n            $this->linkID->exec(\n                $this->parseSavepointRollBack('trans' . $this->transTimes)\n            );\n        }\n\n        $this->transTimes = max(0, $this->transTimes - 1);\n    }\n\n    /**\n     * 是否支持事务嵌套\n     * @return bool\n     */\n    protected function supportSavepoint()\n    {\n        return false;\n    }\n\n    /**\n     * 生成定义保存点的SQL\n     * @param $name\n     * @return string\n     */\n    protected function parseSavepoint($name)\n    {\n        return 'SAVEPOINT ' . $name;\n    }\n\n    /**\n     * 生成回滚到保存点的SQL\n     * @param $name\n     * @return string\n     */\n    protected function parseSavepointRollBack($name)\n    {\n        return 'ROLLBACK TO SAVEPOINT ' . $name;\n    }\n\n    /**\n     * 批处理执行SQL语句\n     * 批处理的指令都认为是execute操作\n     * @access public\n     * @param array $sqlArray SQL批处理指令\n     * @return boolean\n     */\n    public function batchQuery($sqlArray = [])\n    {\n        if (!is_array($sqlArray)) {\n            return false;\n        }\n        // 自动启动事务支持\n        $this->startTrans();\n        try {\n            foreach ($sqlArray as $sql) {\n                $this->execute($sql);\n            }\n            // 提交事务\n            $this->commit();\n        } catch (\\Exception $e) {\n            $this->rollback();\n            throw $e;\n        }\n        return true;\n    }\n\n    /**\n     * 获得查询次数\n     * @access public\n     * @param boolean $execute 是否包含所有查询\n     * @return integer\n     */\n    public function getQueryTimes($execute = false)\n    {\n        return $execute ? Db::$queryTimes + Db::$executeTimes : Db::$queryTimes;\n    }\n\n    /**\n     * 获得执行次数\n     * @access public\n     * @return integer\n     */\n    public function getExecuteTimes()\n    {\n        return Db::$executeTimes;\n    }\n\n    /**\n     * 关闭数据库（或者重新连接）\n     * @access public\n     * @return $this\n     */\n    public function close()\n    {\n        $this->linkID    = null;\n        $this->linkWrite = null;\n        $this->linkRead  = null;\n        $this->links     = [];\n        return $this;\n    }\n\n    /**\n     * 是否断线\n     * @access protected\n     * @param \\PDOException  $e 异常对象\n     * @return bool\n     */\n    protected function isBreak($e)\n    {\n        if (!$this->config['break_reconnect']) {\n            return false;\n        }\n\n        $info = [\n            'server has gone away',\n            'no connection to the server',\n            'Lost connection',\n            'is dead or not enabled',\n            'Error while sending',\n            'decryption failed or bad record mac',\n            'server closed the connection unexpectedly',\n            'SSL connection has been closed unexpectedly',\n            'Error writing data to the connection',\n            'Resource deadlock avoided',\n        ];\n\n        $error = $e->getMessage();\n\n        foreach ($info as $msg) {\n            if (false !== stripos($error, $msg)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 获取最近一次查询的sql语句\n     * @access public\n     * @return string\n     */\n    public function getLastSql()\n    {\n        return $this->getRealSql($this->queryStr, $this->bind);\n    }\n\n    /**\n     * 获取最近插入的ID\n     * @access public\n     * @param string  $sequence     自增序列名\n     * @return string\n     */\n    public function getLastInsID($sequence = null)\n    {\n        return $this->linkID->lastInsertId($sequence);\n    }\n\n    /**\n     * 获取返回或者影响的记录数\n     * @access public\n     * @return integer\n     */\n    public function getNumRows()\n    {\n        return $this->numRows;\n    }\n\n    /**\n     * 获取最近的错误信息\n     * @access public\n     * @return string\n     */\n    public function getError()\n    {\n        if ($this->PDOStatement) {\n            $error = $this->PDOStatement->errorInfo();\n            $error = $error[1] . ':' . $error[2];\n        } else {\n            $error = '';\n        }\n        if ('' != $this->queryStr) {\n            $error .= \"\\n [ SQL语句 ] : \" . $this->getLastsql();\n        }\n        return $error;\n    }\n\n    /**\n     * SQL指令安全过滤\n     * @access public\n     * @param string $str SQL字符串\n     * @param bool   $master 是否主库查询\n     * @return string\n     */\n    public function quote($str, $master = true)\n    {\n        $this->initConnect($master);\n        return $this->linkID ? $this->linkID->quote($str) : $str;\n    }\n\n    /**\n     * 数据库调试 记录当前SQL及分析性能\n     * @access protected\n     * @param boolean $start 调试开始标记 true 开始 false 结束\n     * @param string  $sql 执行的SQL语句 留空自动获取\n     * @return void\n     */\n    protected function debug($start, $sql = '')\n    {\n        if (!empty($this->config['debug'])) {\n            // 开启数据库调试模式\n            if ($start) {\n                Debug::remark('queryStartTime', 'time');\n            } else {\n                // 记录操作结束时间\n                Debug::remark('queryEndTime', 'time');\n                $runtime = Debug::getRangeTime('queryStartTime', 'queryEndTime');\n                $sql     = $sql ?: $this->getLastsql();\n                $result  = [];\n                // SQL性能分析\n                if ($this->config['sql_explain'] && 0 === stripos(trim($sql), 'select')) {\n                    $result = $this->getExplain($sql);\n                }\n                // SQL监听\n                $this->trigger($sql, $runtime, $result);\n            }\n        }\n    }\n\n    /**\n     * 监听SQL执行\n     * @access public\n     * @param callable $callback 回调方法\n     * @return void\n     */\n    public function listen($callback)\n    {\n        self::$event[] = $callback;\n    }\n\n    /**\n     * 触发SQL事件\n     * @access protected\n     * @param string    $sql SQL语句\n     * @param float     $runtime SQL运行时间\n     * @param mixed     $explain SQL分析\n     * @return bool\n     */\n    protected function trigger($sql, $runtime, $explain = [])\n    {\n        if (!empty(self::$event)) {\n            foreach (self::$event as $callback) {\n                if (is_callable($callback)) {\n                    call_user_func_array($callback, [$sql, $runtime, $explain]);\n                }\n            }\n        } else {\n            // 未注册监听则记录到日志中\n            Log::record('[ SQL ] ' . $sql . ' [ RunTime:' . $runtime . 's ]', 'sql');\n            if (!empty($explain)) {\n                Log::record('[ EXPLAIN : ' . var_export($explain, true) . ' ]', 'sql');\n            }\n        }\n    }\n\n    /**\n     * 初始化数据库连接\n     * @access protected\n     * @param boolean $master 是否主服务器\n     * @return void\n     */\n    protected function initConnect($master = true)\n    {\n        if (!empty($this->config['deploy'])) {\n            // 采用分布式数据库\n            if ($master || $this->transTimes) {\n                if (!$this->linkWrite) {\n                    $this->linkWrite = $this->multiConnect(true);\n                }\n                $this->linkID = $this->linkWrite;\n            } else {\n                if (!$this->linkRead) {\n                    $this->linkRead = $this->multiConnect(false);\n                }\n                $this->linkID = $this->linkRead;\n            }\n        } elseif (!$this->linkID) {\n            // 默认单数据库\n            $this->linkID = $this->connect();\n        }\n    }\n\n    /**\n     * 连接分布式服务器\n     * @access protected\n     * @param boolean $master 主服务器\n     * @return PDO\n     */\n    protected function multiConnect($master = false)\n    {\n        $_config = [];\n        // 分布式数据库配置解析\n        foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) {\n            $_config[$name] = explode(',', $this->config[$name]);\n        }\n\n        // 主服务器序号\n        $m = floor(mt_rand(0, $this->config['master_num'] - 1));\n\n        if ($this->config['rw_separate']) {\n            // 主从式采用读写分离\n            if ($master) // 主服务器写入\n            {\n                $r = $m;\n            } elseif (is_numeric($this->config['slave_no'])) {\n                // 指定服务器读\n                $r = $this->config['slave_no'];\n            } else {\n                // 读操作连接从服务器 每次随机连接的数据库\n                $r = floor(mt_rand($this->config['master_num'], count($_config['hostname']) - 1));\n            }\n        } else {\n            // 读写操作不区分服务器 每次随机连接的数据库\n            $r = floor(mt_rand(0, count($_config['hostname']) - 1));\n        }\n        $dbMaster = false;\n        if ($m != $r) {\n            $dbMaster = [];\n            foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) {\n                $dbMaster[$name] = isset($_config[$name][$m]) ? $_config[$name][$m] : $_config[$name][0];\n            }\n        }\n        $dbConfig = [];\n        foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) {\n            $dbConfig[$name] = isset($_config[$name][$r]) ? $_config[$name][$r] : $_config[$name][0];\n        }\n        return $this->connect($dbConfig, $r, $r == $m ? false : $dbMaster);\n    }\n\n    /**\n     * 析构方法\n     * @access public\n     */\n    public function __destruct()\n    {\n        // 释放查询\n        if ($this->PDOStatement) {\n            $this->free();\n        }\n        // 关闭连接\n        $this->close();\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/Query.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db;\n\nuse PDO;\nuse think\\Cache;\nuse think\\Collection;\nuse think\\Config;\nuse think\\Db;\nuse think\\db\\exception\\BindParamException;\nuse think\\db\\exception\\DataNotFoundException;\nuse think\\db\\exception\\ModelNotFoundException;\nuse think\\Exception;\nuse think\\exception\\DbException;\nuse think\\exception\\PDOException;\nuse think\\Loader;\nuse think\\Model;\nuse think\\model\\Relation;\nuse think\\model\\relation\\OneToOne;\nuse think\\Paginator;\n\nclass Query\n{\n    // 数据库Connection对象实例\n    protected $connection;\n    // 数据库Builder对象实例\n    protected $builder;\n    // 当前模型类名称\n    protected $model;\n    // 当前数据表名称（含前缀）\n    protected $table = '';\n    // 当前数据表名称（不含前缀）\n    protected $name = '';\n    // 当前数据表主键\n    protected $pk;\n    // 当前数据表前缀\n    protected $prefix = '';\n    // 查询参数\n    protected $options = [];\n    // 参数绑定\n    protected $bind = [];\n    // 数据表信息\n    protected static $info = [];\n    // 回调事件\n    private static $event = [];\n\n    /**\n     * 构造函数\n     * @access public\n     * @param Connection $connection 数据库对象实例\n     * @param string     $model      模型名\n     */\n    public function __construct(Connection $connection = null, $model = '')\n    {\n        $this->connection = $connection ?: Db::connect([], true);\n        $this->prefix     = $this->connection->getConfig('prefix');\n        $this->model      = $model;\n        // 设置当前连接的Builder对象\n        $this->setBuilder();\n    }\n\n    /**\n     * 利用__call方法实现一些特殊的Model方法\n     * @access public\n     * @param string $method 方法名称\n     * @param array  $args   调用参数\n     * @return mixed\n     * @throws DbException\n     * @throws Exception\n     */\n    public function __call($method, $args)\n    {\n        if (strtolower(substr($method, 0, 5)) == 'getby') {\n            // 根据某个字段获取记录\n            $field         = Loader::parseName(substr($method, 5));\n            $where[$field] = $args[0];\n            return $this->where($where)->find();\n        } elseif (strtolower(substr($method, 0, 10)) == 'getfieldby') {\n            // 根据某个字段获取记录的某个值\n            $name         = Loader::parseName(substr($method, 10));\n            $where[$name] = $args[0];\n            return $this->where($where)->value($args[1]);\n        } else {\n            throw new Exception('method not exist:' . __CLASS__ . '->' . $method);\n        }\n    }\n\n    /**\n     * 获取当前的数据库Connection对象\n     * @access public\n     * @return Connection\n     */\n    public function getConnection()\n    {\n        return $this->connection;\n    }\n\n    /**\n     * 切换当前的数据库连接\n     * @access public\n     * @param mixed $config\n     * @return $this\n     */\n    public function connect($config)\n    {\n        $this->connection = Db::connect($config);\n        $this->setBuilder();\n        return $this;\n    }\n\n    /**\n     * 设置当前的数据库Builder对象\n     * @access protected\n     * @return void\n     */\n    protected function setBuilder()\n    {\n        $class         = $this->connection->getBuilder();\n        $this->builder = new $class($this->connection, $this);\n    }\n\n    /**\n     * 获取当前的模型对象名\n     * @access public\n     * @return string\n     */\n    public function getModel()\n    {\n        return $this->model;\n    }\n\n    /**\n     * 获取当前的builder实例对象\n     * @access public\n     * @return Builder\n     */\n    public function getBuilder()\n    {\n        return $this->builder;\n    }\n\n    /**\n     * 指定默认的数据表名（不含前缀）\n     * @access public\n     * @param string $name\n     * @return $this\n     */\n    public function name($name)\n    {\n        $this->name = $name;\n        return $this;\n    }\n\n    /**\n     * 指定默认数据表名（含前缀）\n     * @access public\n     * @param string $table 表名\n     * @return $this\n     */\n    public function setTable($table)\n    {\n        $this->table = $table;\n        return $this;\n    }\n\n    /**\n     * 得到当前或者指定名称的数据表\n     * @access public\n     * @param string $name\n     * @return string\n     */\n    public function getTable($name = '')\n    {\n        if ($name || empty($this->table)) {\n            $name      = $name ?: $this->name;\n            $tableName = $this->prefix;\n            if ($name) {\n                $tableName .= Loader::parseName($name);\n            }\n        } else {\n            $tableName = $this->table;\n        }\n        return $tableName;\n    }\n\n    /**\n     * 将SQL语句中的__TABLE_NAME__字符串替换成带前缀的表名（小写）\n     * @access public\n     * @param string $sql sql语句\n     * @return string\n     */\n    public function parseSqlTable($sql)\n    {\n        if (false !== strpos($sql, '__')) {\n            $prefix = $this->prefix;\n            $sql    = preg_replace_callback(\"/__([A-Z0-9_-]+)__/sU\", function ($match) use ($prefix) {\n                return $prefix . strtolower($match[1]);\n            }, $sql);\n        }\n        return $sql;\n    }\n\n    /**\n     * 执行查询 返回数据集\n     * @access public\n     * @param string      $sql    sql指令\n     * @param array       $bind   参数绑定\n     * @param boolean     $master 是否在主服务器读操作\n     * @param bool|string $class  指定返回的数据集对象\n     * @return mixed\n     * @throws BindParamException\n     * @throws PDOException\n     */\n    public function query($sql, $bind = [], $master = false, $class = false)\n    {\n        return $this->connection->query($sql, $bind, $master, $class);\n    }\n\n    /**\n     * 执行语句\n     * @access public\n     * @param string $sql  sql指令\n     * @param array  $bind 参数绑定\n     * @return int\n     * @throws BindParamException\n     * @throws PDOException\n     */\n    public function execute($sql, $bind = [])\n    {\n        return $this->connection->execute($sql, $bind);\n    }\n\n    /**\n     * 获取最近插入的ID\n     * @access public\n     * @param string $sequence 自增序列名\n     * @return string\n     */\n    public function getLastInsID($sequence = null)\n    {\n        return $this->connection->getLastInsID($sequence);\n    }\n\n    /**\n     * 获取最近一次查询的sql语句\n     * @access public\n     * @return string\n     */\n    public function getLastSql()\n    {\n        return $this->connection->getLastSql();\n    }\n\n    /**\n     * 执行数据库事务\n     * @access public\n     * @param callable $callback 数据操作方法回调\n     * @return mixed\n     */\n    public function transaction($callback)\n    {\n        return $this->connection->transaction($callback);\n    }\n\n    /**\n     * 启动事务\n     * @access public\n     * @return void\n     */\n    public function startTrans()\n    {\n        $this->connection->startTrans();\n    }\n\n    /**\n     * 用于非自动提交状态下面的查询提交\n     * @access public\n     * @return void\n     * @throws PDOException\n     */\n    public function commit()\n    {\n        $this->connection->commit();\n    }\n\n    /**\n     * 事务回滚\n     * @access public\n     * @return void\n     * @throws PDOException\n     */\n    public function rollback()\n    {\n        $this->connection->rollback();\n    }\n\n    /**\n     * 批处理执行SQL语句\n     * 批处理的指令都认为是execute操作\n     * @access public\n     * @param array $sql SQL批处理指令\n     * @return boolean\n     */\n    public function batchQuery($sql = [])\n    {\n        return $this->connection->batchQuery($sql);\n    }\n\n    /**\n     * 获取数据库的配置参数\n     * @access public\n     * @param string $name 参数名称\n     * @return boolean\n     */\n    public function getConfig($name = '')\n    {\n        return $this->connection->getConfig($name);\n    }\n\n    /**\n     * 得到分表的的数据表名\n     * @access public\n     * @param array  $data  操作的数据\n     * @param string $field 分表依据的字段\n     * @param array  $rule  分表规则\n     * @return string\n     */\n    public function getPartitionTableName($data, $field, $rule = [])\n    {\n        // 对数据表进行分区\n        if ($field && isset($data[$field])) {\n            $value = $data[$field];\n            $type  = $rule['type'];\n            switch ($type) {\n                case 'id':\n                    // 按照id范围分表\n                    $step = $rule['expr'];\n                    $seq  = floor($value / $step) + 1;\n                    break;\n                case 'year':\n                    // 按照年份分表\n                    if (!is_numeric($value)) {\n                        $value = strtotime($value);\n                    }\n                    $seq = date('Y', $value) - $rule['expr'] + 1;\n                    break;\n                case 'mod':\n                    // 按照id的模数分表\n                    $seq = ($value % $rule['num']) + 1;\n                    break;\n                case 'md5':\n                    // 按照md5的序列分表\n                    $seq = (ord(substr(md5($value), 0, 1)) % $rule['num']) + 1;\n                    break;\n                default:\n                    if (function_exists($type)) {\n                        // 支持指定函数哈希\n                        $seq = (ord(substr($type($value), 0, 1)) % $rule['num']) + 1;\n                    } else {\n                        // 按照字段的首字母的值分表\n                        $seq = (ord($value{0}) % $rule['num']) + 1;\n                    }\n            }\n            return $this->getTable() . '_' . $seq;\n        } else {\n            // 当设置的分表字段不在查询条件或者数据中\n            // 进行联合查询，必须设定 partition['num']\n            $tableName = [];\n            for ($i = 0; $i < $rule['num']; $i++) {\n                $tableName[] = 'SELECT * FROM ' . $this->getTable() . '_' . ($i + 1);\n            }\n\n            $tableName = '( ' . implode(\" UNION \", $tableName) . ') AS ' . $this->name;\n            return $tableName;\n        }\n    }\n\n    /**\n     * 得到某个字段的值\n     * @access public\n     * @param string $field   字段名\n     * @param mixed  $default 默认值\n     * @param bool   $force   强制转为数字类型\n     * @return mixed\n     */\n    public function value($field, $default = null, $force = false)\n    {\n        $result = false;\n        if (empty($this->options['fetch_sql']) && !empty($this->options['cache'])) {\n            // 判断查询缓存\n            $cache = $this->options['cache'];\n            if (empty($this->options['table'])) {\n                $this->options['table'] = $this->getTable();\n            }\n            $key    = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options) . serialize($this->bind));\n            $result = Cache::get($key);\n        }\n        if (false === $result) {\n            if (isset($this->options['field'])) {\n                unset($this->options['field']);\n            }\n            $pdo = $this->field($field)->limit(1)->getPdo();\n            if (is_string($pdo)) {\n                // 返回SQL语句\n                return $pdo;\n            }\n            $result = $pdo->fetchColumn();\n            if ($force) {\n                $result = is_numeric($result) ? $result + 0 : $result;\n            }\n            if (isset($cache)) {\n                // 缓存数据\n                $this->cacheData($key, $result, $cache);\n            }\n        } else {\n            // 清空查询条件\n            $this->options = [];\n        }\n        return false !== $result ? $result : $default;\n    }\n\n    /**\n     * 得到某个列的数组\n     * @access public\n     * @param string $field 字段名 多个字段用逗号分隔\n     * @param string $key   索引\n     * @return array\n     */\n    public function column($field, $key = '')\n    {\n        $result = false;\n        if (empty($this->options['fetch_sql']) && !empty($this->options['cache'])) {\n            // 判断查询缓存\n            $cache = $this->options['cache'];\n            if (empty($this->options['table'])) {\n                $this->options['table'] = $this->getTable();\n            }\n            $guid   = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options) . serialize($this->bind));\n            $result = Cache::get($guid);\n        }\n        if (false === $result) {\n            if (isset($this->options['field'])) {\n                unset($this->options['field']);\n            }\n            if (is_null($field)) {\n                $field = '*';\n            } elseif ($key && '*' != $field) {\n                $field = $key . ',' . $field;\n            }\n            $pdo = $this->field($field)->getPdo();\n            if (is_string($pdo)) {\n                // 返回SQL语句\n                return $pdo;\n            }\n            if (1 == $pdo->columnCount()) {\n                $result = $pdo->fetchAll(PDO::FETCH_COLUMN);\n            } else {\n                $resultSet = $pdo->fetchAll(PDO::FETCH_ASSOC);\n                if ($resultSet) {\n                    $fields = array_keys($resultSet[0]);\n                    $count  = count($fields);\n                    $key1   = array_shift($fields);\n                    $key2   = $fields ? array_shift($fields) : '';\n                    $key    = $key ?: $key1;\n                    if (strpos($key, '.')) {\n                        list($alias, $key) = explode('.', $key);\n                    }\n                    foreach ($resultSet as $val) {\n                        if ($count > 2) {\n                            $result[$val[$key]] = $val;\n                        } elseif (2 == $count) {\n                            $result[$val[$key]] = $val[$key2];\n                        } elseif (1 == $count) {\n                            $result[$val[$key]] = $val[$key1];\n                        }\n                    }\n                } else {\n                    $result = [];\n                }\n            }\n            if (isset($cache) && isset($guid)) {\n                // 缓存数据\n                $this->cacheData($guid, $result, $cache);\n            }\n        } else {\n            // 清空查询条件\n            $this->options = [];\n        }\n        return $result;\n    }\n\n    /**\n     * COUNT查询\n     * @access public\n     * @param string $field 字段名\n     * @return integer|string\n     */\n    public function count($field = '*')\n    {\n        if (isset($this->options['group'])) {\n            // 支持GROUP\n            $options = $this->getOptions();\n            $subSql  = $this->options($options)->field('count(' . $field . ')')->bind($this->bind)->buildSql();\n            return $this->table([$subSql => '_group_count_'])->value('COUNT(*) AS tp_count', 0, true);\n        }\n\n        return $this->value('COUNT(' . $field . ') AS tp_count', 0, true);\n    }\n\n    /**\n     * SUM查询\n     * @access public\n     * @param string $field 字段名\n     * @return float|int\n     */\n    public function sum($field)\n    {\n        return $this->value('SUM(' . $field . ') AS tp_sum', 0, true);\n    }\n\n    /**\n     * MIN查询\n     * @access public\n     * @param string $field 字段名\n     * @return mixed\n     */\n    public function min($field)\n    {\n        return $this->value('MIN(' . $field . ') AS tp_min', 0, true);\n    }\n\n    /**\n     * MAX查询\n     * @access public\n     * @param string $field 字段名\n     * @return mixed\n     */\n    public function max($field)\n    {\n        return $this->value('MAX(' . $field . ') AS tp_max', 0, true);\n    }\n\n    /**\n     * AVG查询\n     * @access public\n     * @param string $field 字段名\n     * @return float|int\n     */\n    public function avg($field)\n    {\n        return $this->value('AVG(' . $field . ') AS tp_avg', 0, true);\n    }\n\n    /**\n     * 设置记录的某个字段值\n     * 支持使用数据库字段和方法\n     * @access public\n     * @param string|array $field 字段名\n     * @param mixed        $value 字段值\n     * @return integer\n     */\n    public function setField($field, $value = '')\n    {\n        if (is_array($field)) {\n            $data = $field;\n        } else {\n            $data[$field] = $value;\n        }\n        return $this->update($data);\n    }\n\n    /**\n     * 字段值(延迟)增长\n     * @access public\n     * @param string  $field    字段名\n     * @param integer $step     增长值\n     * @param integer $lazyTime 延时时间(s)\n     * @return integer|true\n     * @throws Exception\n     */\n    public function setInc($field, $step = 1, $lazyTime = 0)\n    {\n        $condition = !empty($this->options['where']) ? $this->options['where'] : [];\n        if (empty($condition)) {\n            // 没有条件不做任何更新\n            throw new Exception('no data to update');\n        }\n        if ($lazyTime > 0) {\n            // 延迟写入\n            $guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition) . serialize($this->bind));\n            $step = $this->lazyWrite('inc', $guid, $step, $lazyTime);\n            if (false === $step) {\n                // 清空查询条件\n                $this->options = [];\n                return true;\n            }\n        }\n        return $this->setField($field, ['exp', $field . '+' . $step]);\n    }\n\n    /**\n     * 字段值（延迟）减少\n     * @access public\n     * @param string  $field    字段名\n     * @param integer $step     减少值\n     * @param integer $lazyTime 延时时间(s)\n     * @return integer|true\n     * @throws Exception\n     */\n    public function setDec($field, $step = 1, $lazyTime = 0)\n    {\n        $condition = !empty($this->options['where']) ? $this->options['where'] : [];\n        if (empty($condition)) {\n            // 没有条件不做任何更新\n            throw new Exception('no data to update');\n        }\n        if ($lazyTime > 0) {\n            // 延迟写入\n            $guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition) . serialize($this->bind));\n            $step = $this->lazyWrite('dec', $guid, $step, $lazyTime);\n            if (false === $step) {\n                // 清空查询条件\n                $this->options = [];\n                return true;\n            }\n        }\n        return $this->setField($field, ['exp', $field . '-' . $step]);\n    }\n\n    /**\n     * 延时更新检查 返回false表示需要延时\n     * 否则返回实际写入的数值\n     * @access protected\n     * @param string  $type     自增或者自减\n     * @param string  $guid     写入标识\n     * @param integer $step     写入步进值\n     * @param integer $lazyTime 延时时间(s)\n     * @return false|integer\n     */\n    protected function lazyWrite($type, $guid, $step, $lazyTime)\n    {\n        if (!Cache::has($guid . '_time')) {\n            // 计时开始\n            Cache::set($guid . '_time', $_SERVER['REQUEST_TIME'], 0);\n            Cache::$type($guid, $step);\n        } elseif ($_SERVER['REQUEST_TIME'] > Cache::get($guid . '_time') + $lazyTime) {\n            // 删除缓存\n            $value = Cache::$type($guid, $step);\n            Cache::rm($guid);\n            Cache::rm($guid . '_time');\n            return 0 === $value ? false : $value;\n        } else {\n            // 更新缓存\n            Cache::$type($guid, $step);\n        }\n        return false;\n    }\n\n    /**\n     * 查询SQL组装 join\n     * @access public\n     * @param mixed  $join      关联的表名\n     * @param mixed  $condition 条件\n     * @param string $type      JOIN类型\n     * @return $this\n     */\n    public function join($join, $condition = null, $type = 'INNER')\n    {\n        if (empty($condition)) {\n            // 如果为组数，则循环调用join\n            foreach ($join as $key => $value) {\n                if (is_array($value) && 2 <= count($value)) {\n                    $this->join($value[0], $value[1], isset($value[2]) ? $value[2] : $type);\n                }\n            }\n        } else {\n            $table = $this->getJoinTable($join);\n\n            $this->options['join'][] = [$table, strtoupper($type), $condition];\n        }\n        return $this;\n    }\n\n    /**\n     * 获取Join表名及别名 支持\n     * ['prefix_table或者子查询'=>'alias'] 'prefix_table alias' 'table alias'\n     * @access public\n     * @param array|string $join\n     * @return array|string\n     */\n    protected function getJoinTable($join, &$alias = null)\n    {\n        // 传入的表名为数组\n        if (is_array($join)) {\n            list($table, $alias) = each($join);\n        } else {\n            $join = trim($join);\n            if (false !== strpos($join, '(')) {\n                // 使用子查询\n                $table = $join;\n            } else {\n                $prefix = $this->prefix;\n                if (strpos($join, ' ')) {\n                    // 使用别名\n                    list($table, $alias) = explode(' ', $join);\n                } else {\n                    $table = $join;\n                    if (false === strpos($join, '.') && 0 !== strpos($join, '__')) {\n                        $alias = $join;\n                    }\n                }\n                if ($prefix && false === strpos($table, '.') && 0 !== strpos($table, $prefix) && 0 !== strpos($table, '__')) {\n                    $table = $this->getTable($table);\n                }\n            }\n        }\n        if (isset($alias)) {\n            if (isset($this->options['alias'][$table])) {\n                $table = $table . '@think' . uniqid();\n            }\n            $table = [$table => $alias];\n            $this->alias($table);\n        }\n        return $table;\n    }\n\n    /**\n     * 查询SQL组装 union\n     * @access public\n     * @param mixed   $union\n     * @param boolean $all\n     * @return $this\n     */\n    public function union($union, $all = false)\n    {\n        $this->options['union']['type'] = $all ? 'UNION ALL' : 'UNION';\n\n        if (is_array($union)) {\n            $this->options['union'] = array_merge($this->options['union'], $union);\n        } else {\n            $this->options['union'][] = $union;\n        }\n        return $this;\n    }\n\n    /**\n     * 指定查询字段 支持字段排除和指定数据表\n     * @access public\n     * @param mixed   $field\n     * @param boolean $except    是否排除\n     * @param string  $tableName 数据表名\n     * @param string  $prefix    字段前缀\n     * @param string  $alias     别名前缀\n     * @return $this\n     */\n    public function field($field, $except = false, $tableName = '', $prefix = '', $alias = '')\n    {\n        if (empty($field)) {\n            return $this;\n        }\n        if (is_string($field)) {\n            $field = array_map('trim', explode(',', $field));\n        }\n        if (true === $field) {\n            // 获取全部字段\n            $fields = $this->getTableInfo($tableName ?: (isset($this->options['table']) ? $this->options['table'] : ''), 'fields');\n            $field  = $fields ?: ['*'];\n        } elseif ($except) {\n            // 字段排除\n            $fields = $this->getTableInfo($tableName ?: (isset($this->options['table']) ? $this->options['table'] : ''), 'fields');\n            $field  = $fields ? array_diff($fields, $field) : $field;\n        }\n        if ($tableName) {\n            // 添加统一的前缀\n            $prefix = $prefix ?: $tableName;\n            foreach ($field as $key => $val) {\n                if (is_numeric($key)) {\n                    $val = $prefix . '.' . $val . ($alias ? ' AS ' . $alias . $val : '');\n                }\n                $field[$key] = $val;\n            }\n        }\n\n        if (isset($this->options['field'])) {\n            $field = array_merge($this->options['field'], $field);\n        }\n        $this->options['field'] = array_unique($field);\n        return $this;\n    }\n\n    /**\n     * 设置数据\n     * @access public\n     * @param mixed $field 字段名或者数据\n     * @param mixed $value 字段值\n     * @return $this\n     */\n    public function data($field, $value = null)\n    {\n        if (is_array($field)) {\n            $this->options['data'] = isset($this->options['data']) ? array_merge($this->options['data'], $field) : $field;\n        } else {\n            $this->options['data'][$field] = $value;\n        }\n        return $this;\n    }\n\n    /**\n     * 字段值增长\n     * @access public\n     * @param string|array $field 字段名\n     * @param integer      $step  增长值\n     * @return $this\n     */\n    public function inc($field, $step = 1)\n    {\n        $fields = is_string($field) ? explode(',', $field) : $field;\n        foreach ($fields as $field) {\n            $this->data($field, ['exp', $field . '+' . $step]);\n        }\n        return $this;\n    }\n\n    /**\n     * 字段值减少\n     * @access public\n     * @param string|array $field 字段名\n     * @param integer      $step  增长值\n     * @return $this\n     */\n    public function dec($field, $step = 1)\n    {\n        $fields = is_string($field) ? explode(',', $field) : $field;\n        foreach ($fields as $field) {\n            $this->data($field, ['exp', $field . '-' . $step]);\n        }\n        return $this;\n    }\n\n    /**\n     * 使用表达式设置数据\n     * @access public\n     * @param string $field 字段名\n     * @param string $value 字段值\n     * @return $this\n     */\n    public function exp($field, $value)\n    {\n        $this->data($field, ['exp', $value]);\n        return $this;\n    }\n\n    /**\n     * 指定JOIN查询字段\n     * @access public\n     * @param string|array $table 数据表\n     * @param string|array $field 查询字段\n     * @param string|array $on    JOIN条件\n     * @param string       $type  JOIN类型\n     * @return $this\n     */\n    public function view($join, $field = true, $on = null, $type = 'INNER')\n    {\n        $this->options['view'] = true;\n        if (is_array($join) && key($join) !== 0) {\n            foreach ($join as $key => $val) {\n                $this->view($key, $val[0], isset($val[1]) ? $val[1] : null, isset($val[2]) ? $val[2] : 'INNER');\n            }\n        } else {\n            $fields = [];\n            $table  = $this->getJoinTable($join, $alias);\n\n            if (true === $field) {\n                $fields = $alias . '.*';\n            } else {\n                if (is_string($field)) {\n                    $field = explode(',', $field);\n                }\n                foreach ($field as $key => $val) {\n                    if (is_numeric($key)) {\n                        $fields[]                   = $alias . '.' . $val;\n                        $this->options['map'][$val] = $alias . '.' . $val;\n                    } else {\n                        if (preg_match('/[,=\\.\\'\\\"\\(\\s]/', $key)) {\n                            $name = $key;\n                        } else {\n                            $name = $alias . '.' . $key;\n                        }\n                        $fields[$name]              = $val;\n                        $this->options['map'][$val] = $name;\n                    }\n                }\n            }\n            $this->field($fields);\n            if ($on) {\n                $this->join($table, $on, $type);\n            } else {\n                $this->table($table);\n            }\n        }\n        return $this;\n    }\n\n    /**\n     * 设置分表规则\n     * @access public\n     * @param array  $data  操作的数据\n     * @param string $field 分表依据的字段\n     * @param array  $rule  分表规则\n     * @return $this\n     */\n    public function partition($data, $field, $rule = [])\n    {\n        $this->options['table'] = $this->getPartitionTableName($data, $field, $rule);\n        return $this;\n    }\n\n    /**\n     * 指定AND查询条件\n     * @access public\n     * @param mixed $field     查询字段\n     * @param mixed $op        查询表达式\n     * @param mixed $condition 查询条件\n     * @return $this\n     */\n    public function where($field, $op = null, $condition = null)\n    {\n        $param = func_get_args();\n        array_shift($param);\n        $this->parseWhereExp('AND', $field, $op, $condition, $param);\n        return $this;\n    }\n\n    /**\n     * 指定OR查询条件\n     * @access public\n     * @param mixed $field     查询字段\n     * @param mixed $op        查询表达式\n     * @param mixed $condition 查询条件\n     * @return $this\n     */\n    public function whereOr($field, $op = null, $condition = null)\n    {\n        $param = func_get_args();\n        array_shift($param);\n        $this->parseWhereExp('OR', $field, $op, $condition, $param);\n        return $this;\n    }\n\n    /**\n     * 指定XOR查询条件\n     * @access public\n     * @param mixed $field     查询字段\n     * @param mixed $op        查询表达式\n     * @param mixed $condition 查询条件\n     * @return $this\n     */\n    public function whereXor($field, $op = null, $condition = null)\n    {\n        $param = func_get_args();\n        array_shift($param);\n        $this->parseWhereExp('XOR', $field, $op, $condition, $param);\n        return $this;\n    }\n\n    /**\n     * 指定Null查询条件\n     * @access public\n     * @param mixed  $field 查询字段\n     * @param string $logic 查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereNull($field, $logic = 'AND')\n    {\n        $this->parseWhereExp($logic, $field, 'null', null);\n        return $this;\n    }\n\n    /**\n     * 指定NotNull查询条件\n     * @access public\n     * @param mixed  $field 查询字段\n     * @param string $logic 查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereNotNull($field, $logic = 'AND')\n    {\n        $this->parseWhereExp($logic, $field, 'notnull', null);\n        return $this;\n    }\n\n    /**\n     * 指定Exists查询条件\n     * @access public\n     * @param mixed  $condition 查询条件\n     * @param string $logic     查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereExists($condition, $logic = 'AND')\n    {\n        $this->options['where'][strtoupper($logic)][] = ['exists', $condition];\n        return $this;\n    }\n\n    /**\n     * 指定NotExists查询条件\n     * @access public\n     * @param mixed  $condition 查询条件\n     * @param string $logic     查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereNotExists($condition, $logic = 'AND')\n    {\n        $this->options['where'][strtoupper($logic)][] = ['not exists', $condition];\n        return $this;\n    }\n\n    /**\n     * 指定In查询条件\n     * @access public\n     * @param mixed  $field     查询字段\n     * @param mixed  $condition 查询条件\n     * @param string $logic     查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereIn($field, $condition, $logic = 'AND')\n    {\n        $this->parseWhereExp($logic, $field, 'in', $condition);\n        return $this;\n    }\n\n    /**\n     * 指定NotIn查询条件\n     * @access public\n     * @param mixed  $field     查询字段\n     * @param mixed  $condition 查询条件\n     * @param string $logic     查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereNotIn($field, $condition, $logic = 'AND')\n    {\n        $this->parseWhereExp($logic, $field, 'not in', $condition);\n        return $this;\n    }\n\n    /**\n     * 指定Like查询条件\n     * @access public\n     * @param mixed  $field     查询字段\n     * @param mixed  $condition 查询条件\n     * @param string $logic     查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereLike($field, $condition, $logic = 'AND')\n    {\n        $this->parseWhereExp($logic, $field, 'like', $condition);\n        return $this;\n    }\n\n    /**\n     * 指定NotLike查询条件\n     * @access public\n     * @param mixed  $field     查询字段\n     * @param mixed  $condition 查询条件\n     * @param string $logic     查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereNotLike($field, $condition, $logic = 'AND')\n    {\n        $this->parseWhereExp($logic, $field, 'not like', $condition);\n        return $this;\n    }\n\n    /**\n     * 指定Between查询条件\n     * @access public\n     * @param mixed  $field     查询字段\n     * @param mixed  $condition 查询条件\n     * @param string $logic     查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereBetween($field, $condition, $logic = 'AND')\n    {\n        $this->parseWhereExp($logic, $field, 'between', $condition);\n        return $this;\n    }\n\n    /**\n     * 指定NotBetween查询条件\n     * @access public\n     * @param mixed  $field     查询字段\n     * @param mixed  $condition 查询条件\n     * @param string $logic     查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereNotBetween($field, $condition, $logic = 'AND')\n    {\n        $this->parseWhereExp($logic, $field, 'not between', $condition);\n        return $this;\n    }\n\n    /**\n     * 指定Exp查询条件\n     * @access public\n     * @param mixed  $field     查询字段\n     * @param mixed  $condition 查询条件\n     * @param string $logic     查询逻辑 and or xor\n     * @return $this\n     */\n    public function whereExp($field, $condition, $logic = 'AND')\n    {\n        $this->parseWhereExp($logic, $field, 'exp', $condition);\n        return $this;\n    }\n\n    /**\n     * 设置软删除字段及条件\n     * @access public\n     * @param false|string  $field     查询字段\n     * @param mixed         $condition 查询条件\n     * @return $this\n     */\n    public function useSoftDelete($field, $condition = null)\n    {\n        if ($field) {\n            $this->options['soft_delete'] = [$field, $condition ?: ['null', '']];\n        }\n        return $this;\n    }\n\n    /**\n     * 分析查询表达式\n     * @access public\n     * @param string                $logic     查询逻辑 and or xor\n     * @param string|array|\\Closure $field     查询字段\n     * @param mixed                 $op        查询表达式\n     * @param mixed                 $condition 查询条件\n     * @param array                 $param     查询参数\n     * @return void\n     */\n    protected function parseWhereExp($logic, $field, $op, $condition, $param = [])\n    {\n        $logic = strtoupper($logic);\n        if ($field instanceof \\Closure) {\n            $this->options['where'][$logic][] = is_string($op) ? [$op, $field] : $field;\n            return;\n        }\n\n        if (is_string($field) && !empty($this->options['via']) && !strpos($field, '.')) {\n            $field = $this->options['via'] . '.' . $field;\n        }\n        if (is_string($field) && preg_match('/[,=\\>\\<\\'\\\"\\(\\s]/', $field)) {\n            $where[] = ['exp', $field];\n            if (is_array($op)) {\n                // 参数绑定\n                $this->bind($op);\n            }\n        } elseif (is_null($op) && is_null($condition)) {\n            if (is_array($field)) {\n                // 数组批量查询\n                $where = $field;\n                foreach ($where as $k => $val) {\n                    $this->options['multi'][$logic][$k][] = $val;\n                }\n            } elseif ($field && is_string($field)) {\n                // 字符串查询\n                $where[$field]                            = ['null', ''];\n                $this->options['multi'][$logic][$field][] = $where[$field];\n            }\n        } elseif (is_array($op)) {\n            $where[$field] = $param;\n        } elseif (in_array(strtolower($op), ['null', 'notnull', 'not null'])) {\n            // null查询\n            $where[$field]                            = [$op, ''];\n            $this->options['multi'][$logic][$field][] = $where[$field];\n        } elseif (is_null($condition)) {\n            // 字段相等查询\n            $where[$field] = ['eq', $op];\n            if ('AND' != $logic) {\n                $this->options['multi'][$logic][$field][] = $where[$field];\n            }\n        } else {\n            $where[$field] = [$op, $condition, isset($param[2]) ? $param[2] : null];\n            if ('exp' == strtolower($op) && isset($param[2]) && is_array($param[2])) {\n                // 参数绑定\n                $this->bind($param[2]);\n            }\n            // 记录一个字段多次查询条件\n            $this->options['multi'][$logic][$field][] = $where[$field];\n        }\n        if (!empty($where)) {\n            if (!isset($this->options['where'][$logic])) {\n                $this->options['where'][$logic] = [];\n            }\n            if (is_string($field) && $this->checkMultiField($field, $logic)) {\n                $where[$field] = $this->options['multi'][$logic][$field];\n            } elseif (is_array($field)) {\n                foreach ($field as $key => $val) {\n                    if ($this->checkMultiField($key, $logic)) {\n                        $where[$key] = $this->options['multi'][$logic][$key];\n                    }\n                }\n            }\n            $this->options['where'][$logic] = array_merge($this->options['where'][$logic], $where);\n        }\n    }\n\n    /**\n     * 检查是否存在一个字段多次查询条件\n     * @access public\n     * @param string $field 查询字段\n     * @param string $logic 查询逻辑 and or xor\n     * @return bool\n     */\n    private function checkMultiField($field, $logic)\n    {\n        return isset($this->options['multi'][$logic][$field]) && count($this->options['multi'][$logic][$field]) > 1;\n    }\n\n    /**\n     * 去除某个查询条件\n     * @access public\n     * @param string $field 查询字段\n     * @param string $logic 查询逻辑 and or xor\n     * @return $this\n     */\n    public function removeWhereField($field, $logic = 'AND')\n    {\n        $logic = strtoupper($logic);\n        if (isset($this->options['where'][$logic][$field])) {\n            unset($this->options['where'][$logic][$field]);\n        }\n        return $this;\n    }\n\n    /**\n     * 去除查询参数\n     * @access public\n     * @param string|bool $option 参数名 true 表示去除所有参数\n     * @return $this\n     */\n    public function removeOption($option = true)\n    {\n        if (true === $option) {\n            $this->options = [];\n        } elseif (is_string($option) && isset($this->options[$option])) {\n            unset($this->options[$option]);\n        }\n        return $this;\n    }\n\n    /**\n     * 指定查询数量\n     * @access public\n     * @param mixed $offset 起始位置\n     * @param mixed $length 查询数量\n     * @return $this\n     */\n    public function limit($offset, $length = null)\n    {\n        if (is_null($length) && strpos($offset, ',')) {\n            list($offset, $length) = explode(',', $offset);\n        }\n        $this->options['limit'] = intval($offset) . ($length ? ',' . intval($length) : '');\n        return $this;\n    }\n\n    /**\n     * 指定分页\n     * @access public\n     * @param mixed $page     页数\n     * @param mixed $listRows 每页数量\n     * @return $this\n     */\n    public function page($page, $listRows = null)\n    {\n        if (is_null($listRows) && strpos($page, ',')) {\n            list($page, $listRows) = explode(',', $page);\n        }\n        $this->options['page'] = [intval($page), intval($listRows)];\n        return $this;\n    }\n\n    /**\n     * 分页查询\n     * @param int|array $listRows 每页数量 数组表示配置参数\n     * @param int|bool  $simple   是否简洁模式或者总记录数\n     * @param array     $config   配置参数\n     *                            page:当前页,\n     *                            path:url路径,\n     *                            query:url额外参数,\n     *                            fragment:url锚点,\n     *                            var_page:分页变量,\n     *                            list_rows:每页数量\n     *                            type:分页类名\n     * @return \\think\\Paginator\n     * @throws DbException\n     */\n    public function paginate($listRows = null, $simple = false, $config = [])\n    {\n        if (is_int($simple)) {\n            $total  = $simple;\n            $simple = false;\n        }\n        if (is_array($listRows)) {\n            $config   = array_merge(Config::get('paginate'), $listRows);\n            $listRows = $config['list_rows'];\n        } else {\n            $config   = array_merge(Config::get('paginate'), $config);\n            $listRows = $listRows ?: $config['list_rows'];\n        }\n\n        /** @var Paginator $class */\n        $class = false !== strpos($config['type'], '\\\\') ? $config['type'] : '\\\\think\\\\paginator\\\\driver\\\\' . ucwords($config['type']);\n        $page  = isset($config['page']) ? (int) $config['page'] : call_user_func([\n            $class,\n            'getCurrentPage',\n        ], $config['var_page']);\n\n        $page = $page < 1 ? 1 : $page;\n\n        $config['path'] = isset($config['path']) ? $config['path'] : call_user_func([$class, 'getCurrentPath']);\n\n        if (!isset($total) && !$simple) {\n            $options = $this->getOptions();\n\n            unset($this->options['order'], $this->options['limit'], $this->options['page'], $this->options['field']);\n\n            $bind    = $this->bind;\n            $total   = $this->count();\n            $results = $this->options($options)->bind($bind)->page($page, $listRows)->select();\n        } elseif ($simple) {\n            $results = $this->limit(($page - 1) * $listRows, $listRows + 1)->select();\n            $total   = null;\n        } else {\n            $results = $this->page($page, $listRows)->select();\n        }\n        return $class::make($results, $listRows, $page, $total, $simple, $config);\n    }\n\n    /**\n     * 指定当前操作的数据表\n     * @access public\n     * @param mixed $table 表名\n     * @return $this\n     */\n    public function table($table)\n    {\n        if (is_string($table)) {\n            if (strpos($table, ')')) {\n                // 子查询\n            } elseif (strpos($table, ',')) {\n                $tables = explode(',', $table);\n                $table  = [];\n                foreach ($tables as $item) {\n                    list($item, $alias) = explode(' ', trim($item));\n                    if ($alias) {\n                        $this->alias([$item => $alias]);\n                        $table[$item] = $alias;\n                    } else {\n                        $table[] = $item;\n                    }\n                }\n            } elseif (strpos($table, ' ')) {\n                list($table, $alias) = explode(' ', $table);\n\n                $table = [$table => $alias];\n                $this->alias($table);\n            }\n        } else {\n            $tables = $table;\n            $table  = [];\n            foreach ($tables as $key => $val) {\n                if (is_numeric($key)) {\n                    $table[] = $val;\n                } else {\n                    $this->alias([$key => $val]);\n                    $table[$key] = $val;\n                }\n            }\n        }\n        $this->options['table'] = $table;\n        return $this;\n    }\n\n    /**\n     * USING支持 用于多表删除\n     * @access public\n     * @param mixed $using\n     * @return $this\n     */\n    public function using($using)\n    {\n        $this->options['using'] = $using;\n        return $this;\n    }\n\n    /**\n     * 指定排序 order('id','desc') 或者 order(['id'=>'desc','create_time'=>'desc'])\n     * @access public\n     * @param string|array $field 排序字段\n     * @param string       $order 排序\n     * @return $this\n     */\n    public function order($field, $order = null)\n    {\n        if (!empty($field)) {\n            if (is_string($field)) {\n                if (!empty($this->options['via'])) {\n                    $field = $this->options['via'] . '.' . $field;\n                }\n                $field = empty($order) ? $field : [$field => $order];\n            } elseif (!empty($this->options['via'])) {\n                foreach ($field as $key => $val) {\n                    if (is_numeric($key)) {\n                        $field[$key] = $this->options['via'] . '.' . $val;\n                    } else {\n                        $field[$this->options['via'] . '.' . $key] = $val;\n                        unset($field[$key]);\n                    }\n                }\n            }\n            if (!isset($this->options['order'])) {\n                $this->options['order'] = [];\n            }\n            if (is_array($field)) {\n                $this->options['order'] = array_merge($this->options['order'], $field);\n            } else {\n                $this->options['order'][] = $field;\n            }\n        }\n        return $this;\n    }\n\n    /**\n     * 查询缓存\n     * @access public\n     * @param mixed   $key    缓存key\n     * @param integer $expire 缓存有效期\n     * @param string  $tag    缓存标签\n     * @return $this\n     */\n    public function cache($key = true, $expire = null, $tag = null)\n    {\n        // 增加快捷调用方式 cache(10) 等同于 cache(true, 10)\n        if (is_numeric($key) && is_null($expire)) {\n            $expire = $key;\n            $key    = true;\n        }\n        if (false !== $key) {\n            $this->options['cache'] = ['key' => $key, 'expire' => $expire, 'tag' => $tag];\n        }\n        return $this;\n    }\n\n    /**\n     * 指定group查询\n     * @access public\n     * @param string $group GROUP\n     * @return $this\n     */\n    public function group($group)\n    {\n        $this->options['group'] = $group;\n        return $this;\n    }\n\n    /**\n     * 指定having查询\n     * @access public\n     * @param string $having having\n     * @return $this\n     */\n    public function having($having)\n    {\n        $this->options['having'] = $having;\n        return $this;\n    }\n\n    /**\n     * 指定查询lock\n     * @access public\n     * @param boolean $lock 是否lock\n     * @return $this\n     */\n    public function lock($lock = false)\n    {\n        $this->options['lock']   = $lock;\n        $this->options['master'] = true;\n        return $this;\n    }\n\n    /**\n     * 指定distinct查询\n     * @access public\n     * @param string $distinct 是否唯一\n     * @return $this\n     */\n    public function distinct($distinct)\n    {\n        $this->options['distinct'] = $distinct;\n        return $this;\n    }\n\n    /**\n     * 指定数据表别名\n     * @access public\n     * @param mixed $alias 数据表别名\n     * @return $this\n     */\n    public function alias($alias)\n    {\n        if (is_array($alias)) {\n            foreach ($alias as $key => $val) {\n                $this->options['alias'][$key] = $val;\n            }\n        } else {\n            if (isset($this->options['table'])) {\n                $table = is_array($this->options['table']) ? key($this->options['table']) : $this->options['table'];\n                if (false !== strpos($table, '__')) {\n                    $table = $this->parseSqlTable($table);\n                }\n            } else {\n                $table = $this->getTable();\n            }\n\n            $this->options['alias'][$table] = $alias;\n        }\n        return $this;\n    }\n\n    /**\n     * 指定强制索引\n     * @access public\n     * @param string $force 索引名称\n     * @return $this\n     */\n    public function force($force)\n    {\n        $this->options['force'] = $force;\n        return $this;\n    }\n\n    /**\n     * 查询注释\n     * @access public\n     * @param string $comment 注释\n     * @return $this\n     */\n    public function comment($comment)\n    {\n        $this->options['comment'] = $comment;\n        return $this;\n    }\n\n    /**\n     * 获取执行的SQL语句\n     * @access public\n     * @param boolean $fetch 是否返回sql\n     * @return $this\n     */\n    public function fetchSql($fetch = true)\n    {\n        $this->options['fetch_sql'] = $fetch;\n        return $this;\n    }\n\n    /**\n     * 不主动获取数据集\n     * @access public\n     * @param bool $pdo 是否返回 PDOStatement 对象\n     * @return $this\n     */\n    public function fetchPdo($pdo = true)\n    {\n        $this->options['fetch_pdo'] = $pdo;\n        return $this;\n    }\n\n    /**\n     * 设置从主服务器读取数据\n     * @access public\n     * @return $this\n     */\n    public function master()\n    {\n        $this->options['master'] = true;\n        return $this;\n    }\n\n    /**\n     * 设置是否严格检查字段名\n     * @access public\n     * @param bool $strict 是否严格检查字段\n     * @return $this\n     */\n    public function strict($strict = true)\n    {\n        $this->options['strict'] = $strict;\n        return $this;\n    }\n\n    /**\n     * 设置查询数据不存在是否抛出异常\n     * @access public\n     * @param bool $fail 数据不存在是否抛出异常\n     * @return $this\n     */\n    public function failException($fail = true)\n    {\n        $this->options['fail'] = $fail;\n        return $this;\n    }\n\n    /**\n     * 设置自增序列名\n     * @access public\n     * @param string $sequence 自增序列名\n     * @return $this\n     */\n    public function sequence($sequence = null)\n    {\n        $this->options['sequence'] = $sequence;\n        return $this;\n    }\n\n    /**\n     * 指定数据表主键\n     * @access public\n     * @param string $pk 主键\n     * @return $this\n     */\n    public function pk($pk)\n    {\n        $this->pk = $pk;\n        return $this;\n    }\n\n    /**\n     * 查询日期或者时间\n     * @access public\n     * @param string       $field 日期字段名\n     * @param string       $op    比较运算符或者表达式\n     * @param string|array $range 比较范围\n     * @return $this\n     */\n    public function whereTime($field, $op, $range = null)\n    {\n        if (is_null($range)) {\n            // 使用日期表达式\n            $date = getdate();\n            switch (strtolower($op)) {\n                case 'today':\n                case 'd':\n                    $range = ['today', 'tomorrow'];\n                    break;\n                case 'week':\n                case 'w':\n                    $range = 'this week 00:00:00';\n                    break;\n                case 'month':\n                case 'm':\n                    $range = mktime(0, 0, 0, $date['mon'], 1, $date['year']);\n                    break;\n                case 'year':\n                case 'y':\n                    $range = mktime(0, 0, 0, 1, 1, $date['year']);\n                    break;\n                case 'yesterday':\n                    $range = ['yesterday', 'today'];\n                    break;\n                case 'last week':\n                    $range = ['last week 00:00:00', 'this week 00:00:00'];\n                    break;\n                case 'last month':\n                    $range = [date('y-m-01', strtotime('-1 month')), mktime(0, 0, 0, $date['mon'], 1, $date['year'])];\n                    break;\n                case 'last year':\n                    $range = [mktime(0, 0, 0, 1, 1, $date['year'] - 1), mktime(0, 0, 0, 1, 1, $date['year'])];\n                    break;\n                default:\n                    $range = $op;\n            }\n            $op = is_array($range) ? 'between' : '>';\n        }\n        $this->where($field, strtolower($op) . ' time', $range);\n        return $this;\n    }\n\n    /**\n     * 获取数据表信息\n     * @access public\n     * @param mixed  $tableName 数据表名 留空自动获取\n     * @param string $fetch     获取信息类型 包括 fields type bind pk\n     * @return mixed\n     */\n    public function getTableInfo($tableName = '', $fetch = '')\n    {\n        if (!$tableName) {\n            $tableName = $this->getTable();\n        }\n        if (is_array($tableName)) {\n            $tableName = key($tableName) ?: current($tableName);\n        }\n\n        if (strpos($tableName, ',')) {\n            // 多表不获取字段信息\n            return false;\n        } else {\n            $tableName = $this->parseSqlTable($tableName);\n        }\n\n        // 修正子查询作为表名的问题\n        if (strpos($tableName, ')')) {\n            return [];\n        }\n\n        list($guid) = explode(' ', $tableName);\n        $db         = $this->getConfig('database');\n        if (!isset(self::$info[$db . '.' . $guid])) {\n            if (!strpos($guid, '.')) {\n                $schema = $db . '.' . $guid;\n            } else {\n                $schema = $guid;\n            }\n            // 读取缓存\n            if (is_file(RUNTIME_PATH . 'schema/' . $schema . '.php')) {\n                $info = include RUNTIME_PATH . 'schema/' . $schema . '.php';\n            } else {\n                $info = $this->connection->getFields($guid);\n            }\n            $fields = array_keys($info);\n            $bind   = $type   = [];\n            foreach ($info as $key => $val) {\n                // 记录字段类型\n                $type[$key] = $val['type'];\n                $bind[$key] = $this->getFieldBindType($val['type']);\n                if (!empty($val['primary'])) {\n                    $pk[] = $key;\n                }\n            }\n            if (isset($pk)) {\n                // 设置主键\n                $pk = count($pk) > 1 ? $pk : $pk[0];\n            } else {\n                $pk = null;\n            }\n            self::$info[$db . '.' . $guid] = ['fields' => $fields, 'type' => $type, 'bind' => $bind, 'pk' => $pk];\n        }\n        return $fetch ? self::$info[$db . '.' . $guid][$fetch] : self::$info[$db . '.' . $guid];\n    }\n\n    /**\n     * 获取当前数据表的主键\n     * @access public\n     * @param string|array $options 数据表名或者查询参数\n     * @return string|array\n     */\n    public function getPk($options = '')\n    {\n        if (!empty($this->pk)) {\n            $pk = $this->pk;\n        } else {\n            $pk = $this->getTableInfo(is_array($options) ? $options['table'] : $options, 'pk');\n        }\n        return $pk;\n    }\n\n    // 获取当前数据表字段信息\n    public function getTableFields($table = '')\n    {\n        return $this->getTableInfo($table ?: $this->getOptions('table'), 'fields');\n    }\n\n    // 获取当前数据表字段类型\n    public function getFieldsType($table = '')\n    {\n        return $this->getTableInfo($table ?: $this->getOptions('table'), 'type');\n    }\n\n    // 获取当前数据表绑定信息\n    public function getFieldsBind($table = '')\n    {\n        $types = $this->getFieldsType($table);\n        $bind  = [];\n        if ($types) {\n            foreach ($types as $key => $type) {\n                $bind[$key] = $this->getFieldBindType($type);\n            }\n        }\n        return $bind;\n    }\n\n    /**\n     * 获取字段绑定类型\n     * @access public\n     * @param string $type 字段类型\n     * @return integer\n     */\n    protected function getFieldBindType($type)\n    {\n        if (preg_match('/(int|double|float|decimal|real|numeric|serial|bit)/is', $type)) {\n            $bind = PDO::PARAM_INT;\n        } elseif (preg_match('/bool/is', $type)) {\n            $bind = PDO::PARAM_BOOL;\n        } else {\n            $bind = PDO::PARAM_STR;\n        }\n        return $bind;\n    }\n\n    /**\n     * 参数绑定\n     * @access public\n     * @param mixed   $key   参数名\n     * @param mixed   $value 绑定变量值\n     * @param integer $type  绑定类型\n     * @return $this\n     */\n    public function bind($key, $value = false, $type = PDO::PARAM_STR)\n    {\n        if (is_array($key)) {\n            $this->bind = array_merge($this->bind, $key);\n        } else {\n            $this->bind[$key] = [$value, $type];\n        }\n        return $this;\n    }\n\n    /**\n     * 检测参数是否已经绑定\n     * @access public\n     * @param string $key 参数名\n     * @return bool\n     */\n    public function isBind($key)\n    {\n        return isset($this->bind[$key]);\n    }\n\n    /**\n     * 查询参数赋值\n     * @access protected\n     * @param array $options 表达式参数\n     * @return $this\n     */\n    protected function options(array $options)\n    {\n        $this->options = $options;\n        return $this;\n    }\n\n    /**\n     * 获取当前的查询参数\n     * @access public\n     * @param string $name 参数名\n     * @return mixed\n     */\n    public function getOptions($name = '')\n    {\n        if ('' === $name) {\n            return $this->options;\n        } else {\n            return isset($this->options[$name]) ? $this->options[$name] : null;\n        }\n    }\n\n    /**\n     * 设置关联查询JOIN预查询\n     * @access public\n     * @param string|array $with 关联方法名称\n     * @return $this\n     */\n    public function with($with)\n    {\n        if (empty($with)) {\n            return $this;\n        }\n\n        if (is_string($with)) {\n            $with = explode(',', $with);\n        }\n\n        $first        = true;\n        $currentModel = $this->model;\n\n        /** @var Model $class */\n        $class = new $currentModel;\n        foreach ($with as $key => $relation) {\n            $subRelation = '';\n            $closure     = false;\n            if ($relation instanceof \\Closure) {\n                // 支持闭包查询过滤关联条件\n                $closure    = $relation;\n                $relation   = $key;\n                $with[$key] = $key;\n            } elseif (is_array($relation)) {\n                $subRelation = $relation;\n                $relation    = $key;\n            } elseif (is_string($relation) && strpos($relation, '.')) {\n                $with[$key]                   = $relation;\n                list($relation, $subRelation) = explode('.', $relation, 2);\n            }\n\n            /** @var Relation $model */\n            $relation = Loader::parseName($relation, 1, false);\n            $model    = $class->$relation();\n            if ($model instanceof OneToOne && 0 == $model->getEagerlyType()) {\n                $model->eagerly($this, $relation, $subRelation, $closure, $first);\n                $first = false;\n            } elseif ($closure) {\n                $with[$key] = $closure;\n            }\n        }\n        $this->via();\n        if (isset($this->options['with'])) {\n            $this->options['with'] = array_merge($this->options['with'], $with);\n        } else {\n            $this->options['with'] = $with;\n        }\n        return $this;\n    }\n\n    /**\n     * 关联统计\n     * @access public\n     * @param string|array $relation 关联方法名\n     * @param bool         $subQuery 是否使用子查询\n     * @return $this\n     */\n    public function withCount($relation, $subQuery = true)\n    {\n        if (!$subQuery) {\n            $this->options['with_count'] = $relation;\n        } else {\n            $relations = is_string($relation) ? explode(',', $relation) : $relation;\n            if (!isset($this->options['field'])) {\n                $this->field('*');\n            }\n            foreach ($relations as $key => $relation) {\n                $closure = false;\n                if ($relation instanceof \\Closure) {\n                    $closure  = $relation;\n                    $relation = $key;\n                }\n                $relation = Loader::parseName($relation, 1, false);\n                $count    = '(' . (new $this->model)->$relation()->getRelationCountQuery($closure) . ')';\n                $this->field([$count => Loader::parseName($relation) . '_count']);\n            }\n        }\n        return $this;\n    }\n\n    /**\n     * 关联预加载中 获取关联指定字段值\n     * example:\n     * Model::with(['relation' => function($query){\n     *     $query->withField(\"id,name\");\n     * }])\n     *\n     * @param string | array $field 指定获取的字段\n     * @return $this\n     */\n    public function withField($field)\n    {\n        $this->options['with_field'] = $field;\n        return $this;\n    }\n\n    /**\n     * 设置当前字段添加的表别名\n     * @access public\n     * @param string $via\n     * @return $this\n     */\n    public function via($via = '')\n    {\n        $this->options['via'] = $via;\n        return $this;\n    }\n\n    /**\n     * 设置关联查询\n     * @access public\n     * @param string|array $relation 关联名称\n     * @return $this\n     */\n    public function relation($relation)\n    {\n        if (empty($relation)) {\n            return $this;\n        }\n        if (is_string($relation)) {\n            $relation = explode(',', $relation);\n        }\n        if (isset($this->options['relation'])) {\n            $this->options['relation'] = array_merge($this->options['relation'], $relation);\n        } else {\n            $this->options['relation'] = $relation;\n        }\n        return $this;\n    }\n\n    /**\n     * 把主键值转换为查询条件 支持复合主键\n     * @access public\n     * @param array|string $data    主键数据\n     * @param mixed        $options 表达式参数\n     * @return void\n     * @throws Exception\n     */\n    protected function parsePkWhere($data, &$options)\n    {\n        $pk = $this->getPk($options);\n        // 获取当前数据表\n        $table = is_array($options['table']) ? key($options['table']) : $options['table'];\n        if (!empty($options['alias'][$table])) {\n            $alias = $options['alias'][$table];\n        }\n        if (is_string($pk)) {\n            $key = isset($alias) ? $alias . '.' . $pk : $pk;\n            // 根据主键查询\n            if (is_array($data)) {\n                $where[$key] = isset($data[$pk]) ? $data[$pk] : ['in', $data];\n            } else {\n                $where[$key] = strpos($data, ',') ? ['IN', $data] : $data;\n            }\n        } elseif (is_array($pk) && is_array($data) && !empty($data)) {\n            // 根据复合主键查询\n            foreach ($pk as $key) {\n                if (isset($data[$key])) {\n                    $attr         = isset($alias) ? $alias . '.' . $key : $key;\n                    $where[$attr] = $data[$key];\n                } else {\n                    throw new Exception('miss complex primary data');\n                }\n            }\n        }\n\n        if (!empty($where)) {\n            if (isset($options['where']['AND'])) {\n                $options['where']['AND'] = array_merge($options['where']['AND'], $where);\n            } else {\n                $options['where']['AND'] = $where;\n            }\n        }\n        return;\n    }\n\n    /**\n     * 插入记录\n     * @access public\n     * @param mixed   $data         数据\n     * @param boolean $replace      是否replace\n     * @param boolean $getLastInsID 返回自增主键\n     * @param string  $sequence     自增序列名\n     * @return integer|string\n     */\n    public function insert(array $data = [], $replace = false, $getLastInsID = false, $sequence = null)\n    {\n        // 分析查询表达式\n        $options = $this->parseExpress();\n        $data    = array_merge($options['data'], $data);\n        // 生成SQL语句\n        $sql = $this->builder->insert($data, $options, $replace);\n        // 获取参数绑定\n        $bind = $this->getBind();\n        if ($options['fetch_sql']) {\n            // 获取实际执行的SQL语句\n            return $this->connection->getRealSql($sql, $bind);\n        }\n\n        // 执行操作\n        $result = $this->execute($sql, $bind);\n        if ($result) {\n            $sequence  = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null);\n            $lastInsId = $this->getLastInsID($sequence);\n            if ($lastInsId) {\n                $pk = $this->getPk($options);\n                if (is_string($pk)) {\n                    $data[$pk] = $lastInsId;\n                }\n            }\n            $options['data'] = $data;\n            $this->trigger('after_insert', $options);\n\n            if ($getLastInsID) {\n                return $lastInsId;\n            }\n        }\n        return $result;\n    }\n\n    /**\n     * 插入记录并获取自增ID\n     * @access public\n     * @param mixed   $data     数据\n     * @param boolean $replace  是否replace\n     * @param string  $sequence 自增序列名\n     * @return integer|string\n     */\n    public function insertGetId(array $data, $replace = false, $sequence = null)\n    {\n        return $this->insert($data, $replace, true, $sequence);\n    }\n\n    /**\n     * 批量插入记录\n     * @access public\n     * @param mixed $dataSet 数据集\n     * @param boolean $replace  是否replace\n     * @return integer|string\n     */\n    public function insertAll(array $dataSet, $replace = false)\n    {\n        // 分析查询表达式\n        $options = $this->parseExpress();\n        if (!is_array(reset($dataSet))) {\n            return false;\n        }\n        // 生成SQL语句\n        $sql = $this->builder->insertAll($dataSet, $options, $replace);\n        // 获取参数绑定\n        $bind = $this->getBind();\n        if ($options['fetch_sql']) {\n            // 获取实际执行的SQL语句\n            return $this->connection->getRealSql($sql, $bind);\n        } else {\n            // 执行操作\n            return $this->execute($sql, $bind);\n        }\n    }\n\n    /**\n     * 通过Select方式插入记录\n     * @access public\n     * @param string $fields 要插入的数据表字段名\n     * @param string $table  要插入的数据表名\n     * @return integer|string\n     * @throws PDOException\n     */\n    public function selectInsert($fields, $table)\n    {\n        // 分析查询表达式\n        $options = $this->parseExpress();\n        // 生成SQL语句\n        $table = $this->parseSqlTable($table);\n        $sql   = $this->builder->selectInsert($fields, $table, $options);\n        // 获取参数绑定\n        $bind = $this->getBind();\n        if ($options['fetch_sql']) {\n            // 获取实际执行的SQL语句\n            return $this->connection->getRealSql($sql, $bind);\n        } else {\n            // 执行操作\n            return $this->execute($sql, $bind);\n        }\n    }\n\n    /**\n     * 更新记录\n     * @access public\n     * @param mixed $data 数据\n     * @return integer|string\n     * @throws Exception\n     * @throws PDOException\n     */\n    public function update(array $data = [])\n    {\n        $options = $this->parseExpress();\n        $data    = array_merge($options['data'], $data);\n        $pk      = $this->getPk($options);\n        if (isset($options['cache']) && is_string($options['cache']['key'])) {\n            $key = $options['cache']['key'];\n        }\n\n        if (empty($options['where'])) {\n            // 如果存在主键数据 则自动作为更新条件\n            if (is_string($pk) && isset($data[$pk])) {\n                $where[$pk] = $data[$pk];\n                if (!isset($key)) {\n                    $key = 'think:' . $options['table'] . '|' . $data[$pk];\n                }\n                unset($data[$pk]);\n            } elseif (is_array($pk)) {\n                // 增加复合主键支持\n                foreach ($pk as $field) {\n                    if (isset($data[$field])) {\n                        $where[$field] = $data[$field];\n                    } else {\n                        // 如果缺少复合主键数据则不执行\n                        throw new Exception('miss complex primary data');\n                    }\n                    unset($data[$field]);\n                }\n            }\n            if (!isset($where)) {\n                // 如果没有任何更新条件则不执行\n                throw new Exception('miss update condition');\n            } else {\n                $options['where']['AND'] = $where;\n            }\n        } elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {\n            $key = $this->getCacheKey($options['where']['AND'][$pk], $options, $this->bind);\n        }\n\n        // 生成UPDATE SQL语句\n        $sql = $this->builder->update($data, $options);\n        // 获取参数绑定\n        $bind = $this->getBind();\n        if ($options['fetch_sql']) {\n            // 获取实际执行的SQL语句\n            return $this->connection->getRealSql($sql, $bind);\n        } else {\n            // 检测缓存\n            if (isset($key) && Cache::get($key)) {\n                // 删除缓存\n                Cache::rm($key);\n            } elseif (!empty($options['cache']['tag'])) {\n                Cache::clear($options['cache']['tag']);\n            }\n            // 执行操作\n            $result = '' == $sql ? 0 : $this->execute($sql, $bind);\n            if ($result) {\n                if (is_string($pk) && isset($where[$pk])) {\n                    $data[$pk] = $where[$pk];\n                } elseif (is_string($pk) && isset($key) && strpos($key, '|')) {\n                    list($a, $val) = explode('|', $key);\n                    $data[$pk]     = $val;\n                }\n                $options['data'] = $data;\n                $this->trigger('after_update', $options);\n            }\n            return $result;\n        }\n    }\n\n    /**\n     * 执行查询但只返回PDOStatement对象\n     * @access public\n     * @return \\PDOStatement|string\n     */\n    public function getPdo()\n    {\n        // 分析查询表达式\n        $options = $this->parseExpress();\n        // 生成查询SQL\n        $sql = $this->builder->select($options);\n        // 获取参数绑定\n        $bind = $this->getBind();\n        if ($options['fetch_sql']) {\n            // 获取实际执行的SQL语句\n            return $this->connection->getRealSql($sql, $bind);\n        }\n        // 执行查询操作\n        return $this->query($sql, $bind, $options['master'], true);\n    }\n\n    /**\n     * 查找记录\n     * @access public\n     * @param array|string|Query|\\Closure $data\n     * @return Collection|false|\\PDOStatement|string\n     * @throws DbException\n     * @throws ModelNotFoundException\n     * @throws DataNotFoundException\n     */\n    public function select($data = null)\n    {\n        if ($data instanceof Query) {\n            return $data->select();\n        } elseif ($data instanceof \\Closure) {\n            call_user_func_array($data, [ & $this]);\n            $data = null;\n        }\n        // 分析查询表达式\n        $options = $this->parseExpress();\n\n        if (false === $data) {\n            // 用于子查询 不查询只返回SQL\n            $options['fetch_sql'] = true;\n        } elseif (!is_null($data)) {\n            // 主键条件分析\n            $this->parsePkWhere($data, $options);\n        }\n\n        $resultSet = false;\n        if (empty($options['fetch_sql']) && !empty($options['cache'])) {\n            // 判断查询缓存\n            $cache = $options['cache'];\n            unset($options['cache']);\n            $key       = is_string($cache['key']) ? $cache['key'] : md5(serialize($options) . serialize($this->bind));\n            $resultSet = Cache::get($key);\n        }\n        if (false === $resultSet) {\n            // 生成查询SQL\n            $sql = $this->builder->select($options);\n            // 获取参数绑定\n            $bind = $this->getBind();\n            if ($options['fetch_sql']) {\n                // 获取实际执行的SQL语句\n                return $this->connection->getRealSql($sql, $bind);\n            }\n\n            $options['data'] = $data;\n            if ($resultSet = $this->trigger('before_select', $options)) {\n            } else {\n                // 执行查询操作\n                $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);\n\n                if ($resultSet instanceof \\PDOStatement) {\n                    // 返回PDOStatement对象\n                    return $resultSet;\n                }\n            }\n\n            if (isset($cache) && false !== $resultSet) {\n                // 缓存数据集\n                $this->cacheData($key, $resultSet, $cache);\n            }\n        }\n\n        // 数据列表读取后的处理\n        if (!empty($this->model)) {\n            // 生成模型对象\n            $modelName = $this->model;\n            if (count($resultSet) > 0) {\n                foreach ($resultSet as $key => $result) {\n                    /** @var Model $result */\n                    $model = new $modelName($result);\n                    $model->isUpdate(true);\n\n                    // 关联查询\n                    if (!empty($options['relation'])) {\n                        $model->relationQuery($options['relation']);\n                    }\n                    // 关联统计\n                    if (!empty($options['with_count'])) {\n                        $model->relationCount($model, $options['with_count']);\n                    }\n                    $resultSet[$key] = $model;\n                }\n                if (!empty($options['with'])) {\n                    // 预载入\n                    $model->eagerlyResultSet($resultSet, $options['with']);\n                }\n                // 模型数据集转换\n                $resultSet = $model->toCollection($resultSet);\n            } else {\n                $resultSet = (new $modelName)->toCollection($resultSet);\n            }\n        } elseif ('collection' == $this->connection->getConfig('resultset_type')) {\n            // 返回Collection对象\n            $resultSet = new Collection($resultSet);\n        }\n        // 返回结果处理\n        if (!empty($options['fail']) && count($resultSet) == 0) {\n            $this->throwNotFound($options);\n        }\n        return $resultSet;\n    }\n\n    /**\n     * 缓存数据\n     * @access public\n     * @param string    $key    缓存标识\n     * @param mixed     $data   缓存数据\n     * @param array     $config 缓存参数\n     */\n    protected function cacheData($key, $data, $config = [])\n    {\n        if (isset($config['tag'])) {\n            Cache::tag($config['tag'])->set($key, $data, $config['expire']);\n        } else {\n            Cache::set($key, $data, $config['expire']);\n        }\n    }\n\n    /**\n     * 生成缓存标识\n     * @access public\n     * @param mixed     $value   缓存数据\n     * @param array     $options 缓存参数\n     * @param array     $bind    绑定参数\n     */\n    protected function getCacheKey($value, $options, $bind = [])\n    {\n        if (is_scalar($value)) {\n            $data = $value;\n        } elseif (is_array($value) && 'eq' == strtolower($value[0])) {\n            $data = $value[1];\n        }\n        if (isset($data)) {\n            return 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;\n        } else {\n            return md5(serialize($options) . serialize($bind));\n        }\n    }\n\n    /**\n     * 查找单条记录\n     * @access public\n     * @param array|string|Query|\\Closure $data\n     * @return array|false|\\PDOStatement|string|Model\n     * @throws DbException\n     * @throws ModelNotFoundException\n     * @throws DataNotFoundException\n     */\n    public function find($data = null)\n    {\n        if ($data instanceof Query) {\n            return $data->find();\n        } elseif ($data instanceof \\Closure) {\n            call_user_func_array($data, [ & $this]);\n            $data = null;\n        }\n        // 分析查询表达式\n        $options = $this->parseExpress();\n        $pk      = $this->getPk($options);\n        if (!is_null($data)) {\n            // AR模式分析主键条件\n            $this->parsePkWhere($data, $options);\n        } elseif (!empty($options['cache']) && true === $options['cache']['key'] && is_string($pk) && isset($options['where']['AND'][$pk])) {\n            $key = $this->getCacheKey($options['where']['AND'][$pk], $options, $this->bind);\n        }\n\n        $options['limit'] = 1;\n        $result           = false;\n        if (empty($options['fetch_sql']) && !empty($options['cache'])) {\n            // 判断查询缓存\n            $cache = $options['cache'];\n            if (true === $cache['key'] && !is_null($data) && !is_array($data)) {\n                $key = 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;\n            } elseif (is_string($cache['key'])) {\n                $key = $cache['key'];\n            } elseif (!isset($key)) {\n                $key = md5(serialize($options) . serialize($this->bind));\n            }\n            $result = Cache::get($key);\n        }\n        if (false === $result) {\n            // 生成查询SQL\n            $sql = $this->builder->select($options);\n            // 获取参数绑定\n            $bind = $this->getBind();\n            if ($options['fetch_sql']) {\n                // 获取实际执行的SQL语句\n                return $this->connection->getRealSql($sql, $bind);\n            }\n            if (is_string($pk)) {\n                if (!is_array($data)) {\n                    if (isset($key) && strpos($key, '|')) {\n                        list($a, $val) = explode('|', $key);\n                        $item[$pk]     = $val;\n                    } else {\n                        $item[$pk] = $data;\n                    }\n                    $data = $item;\n                }\n            }\n            $options['data'] = $data;\n            // 事件回调\n            if ($result = $this->trigger('before_find', $options)) {\n            } else {\n                // 执行查询\n                $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);\n\n                if ($resultSet instanceof \\PDOStatement) {\n                    // 返回PDOStatement对象\n                    return $resultSet;\n                }\n                $result = isset($resultSet[0]) ? $resultSet[0] : null;\n            }\n\n            if (isset($cache) && false !== $result) {\n                // 缓存数据\n                $this->cacheData($key, $result, $cache);\n            }\n        }\n\n        // 数据处理\n        if (!empty($result)) {\n            if (!empty($this->model)) {\n                // 返回模型对象\n                $model  = $this->model;\n                $result = new $model($result);\n                $result->isUpdate(true, isset($options['where']['AND']) ? $options['where']['AND'] : null);\n                // 关联查询\n                if (!empty($options['relation'])) {\n                    $result->relationQuery($options['relation']);\n                }\n                // 预载入查询\n                if (!empty($options['with'])) {\n                    $result->eagerlyResult($result, $options['with']);\n                }\n                // 关联统计\n                if (!empty($options['with_count'])) {\n                    $result->relationCount($result, $options['with_count']);\n                }\n            }\n        } elseif (!empty($options['fail'])) {\n            $this->throwNotFound($options);\n        }\n        return $result;\n    }\n\n    /**\n     * 查询失败 抛出异常\n     * @access public\n     * @param array $options 查询参数\n     * @throws ModelNotFoundException\n     * @throws DataNotFoundException\n     */\n    protected function throwNotFound($options = [])\n    {\n        if (!empty($this->model)) {\n            throw new ModelNotFoundException('model data Not Found:' . $this->model, $this->model, $options);\n        } else {\n            $table = is_array($options['table']) ? key($options['table']) : $options['table'];\n            throw new DataNotFoundException('table data not Found:' . $table, $table, $options);\n        }\n    }\n\n    /**\n     * 查找多条记录 如果不存在则抛出异常\n     * @access public\n     * @param array|string|Query|\\Closure $data\n     * @return array|\\PDOStatement|string|Model\n     * @throws DbException\n     * @throws ModelNotFoundException\n     * @throws DataNotFoundException\n     */\n    public function selectOrFail($data = null)\n    {\n        return $this->failException(true)->select($data);\n    }\n\n    /**\n     * 查找单条记录 如果不存在则抛出异常\n     * @access public\n     * @param array|string|Query|\\Closure $data\n     * @return array|\\PDOStatement|string|Model\n     * @throws DbException\n     * @throws ModelNotFoundException\n     * @throws DataNotFoundException\n     */\n    public function findOrFail($data = null)\n    {\n        return $this->failException(true)->find($data);\n    }\n\n    /**\n     * 分批数据返回处理\n     * @access public\n     * @param integer  $count    每次处理的数据数量\n     * @param callable $callback 处理回调方法\n     * @param string   $column   分批处理的字段名\n     * @return boolean\n     */\n    public function chunk($count, $callback, $column = null)\n    {\n        $options = $this->getOptions();\n        if (isset($options['table'])) {\n            $table = is_array($options['table']) ? key($options['table']) : $options['table'];\n        } else {\n            $table = '';\n        }\n        $column    = $column ?: $this->getPk($table);\n        $bind      = $this->bind;\n        $resultSet = $this->limit($count)->order($column, 'asc')->select();\n        if (strpos($column, '.')) {\n            list($alias, $key) = explode('.', $column);\n        } else {\n            $key = $column;\n        }\n        if ($resultSet instanceof Collection) {\n            $resultSet = $resultSet->all();\n        }\n\n        while (!empty($resultSet)) {\n            if (false === call_user_func($callback, $resultSet)) {\n                return false;\n            }\n            $end       = end($resultSet);\n            $lastId    = is_array($end) ? $end[$key] : $end->$key;\n            $resultSet = $this->options($options)\n                ->limit($count)\n                ->bind($bind)\n                ->where($column, '>', $lastId)\n                ->order($column, 'asc')\n                ->select();\n            if ($resultSet instanceof Collection) {\n                $resultSet = $resultSet->all();\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 获取绑定的参数 并清空\n     * @access public\n     * @return array\n     */\n    public function getBind()\n    {\n        $bind       = $this->bind;\n        $this->bind = [];\n        return $bind;\n    }\n\n    /**\n     * 创建子查询SQL\n     * @access public\n     * @param bool $sub\n     * @return string\n     * @throws DbException\n     */\n    public function buildSql($sub = true)\n    {\n        return $sub ? '( ' . $this->select(false) . ' )' : $this->select(false);\n    }\n\n    /**\n     * 删除记录\n     * @access public\n     * @param mixed $data 表达式 true 表示强制删除\n     * @return int\n     * @throws Exception\n     * @throws PDOException\n     */\n    public function delete($data = null)\n    {\n        // 分析查询表达式\n        $options = $this->parseExpress();\n        $pk      = $this->getPk($options);\n        if (isset($options['cache']) && is_string($options['cache']['key'])) {\n            $key = $options['cache']['key'];\n        }\n\n        if (!is_null($data) && true !== $data) {\n            if (!isset($key) && !is_array($data)) {\n                // 缓存标识\n                $key = 'think:' . $options['table'] . '|' . $data;\n            }\n            // AR模式分析主键条件\n            $this->parsePkWhere($data, $options);\n        } elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {\n            $key = $this->getCacheKey($options['where']['AND'][$pk], $options, $this->bind);\n        }\n\n        if (true !== $data && empty($options['where'])) {\n            // 如果条件为空 不进行删除操作 除非设置 1=1\n            throw new Exception('delete without condition');\n        }\n        // 生成删除SQL语句\n        $sql = $this->builder->delete($options);\n        // 获取参数绑定\n        $bind = $this->getBind();\n        if ($options['fetch_sql']) {\n            // 获取实际执行的SQL语句\n            return $this->connection->getRealSql($sql, $bind);\n        }\n\n        // 检测缓存\n        if (isset($key) && Cache::get($key)) {\n            // 删除缓存\n            Cache::rm($key);\n        } elseif (!empty($options['cache']['tag'])) {\n            Cache::clear($options['cache']['tag']);\n        }\n        // 执行操作\n        $result = $this->execute($sql, $bind);\n        if ($result) {\n            if (!is_array($data) && is_string($pk) && isset($key) && strpos($key, '|')) {\n                list($a, $val) = explode('|', $key);\n                $item[$pk]     = $val;\n                $data          = $item;\n            }\n            $options['data'] = $data;\n            $this->trigger('after_delete', $options);\n        }\n        return $result;\n    }\n\n    /**\n     * 分析表达式（可用于查询或者写入操作）\n     * @access protected\n     * @return array\n     */\n    protected function parseExpress()\n    {\n        $options = $this->options;\n\n        // 获取数据表\n        if (empty($options['table'])) {\n            $options['table'] = $this->getTable();\n        }\n\n        if (!isset($options['where'])) {\n            $options['where'] = [];\n        } elseif (isset($options['view'])) {\n            // 视图查询条件处理\n            foreach (['AND', 'OR'] as $logic) {\n                if (isset($options['where'][$logic])) {\n                    foreach ($options['where'][$logic] as $key => $val) {\n                        if (array_key_exists($key, $options['map'])) {\n                            $options['where'][$logic][$options['map'][$key]] = $val;\n                            unset($options['where'][$logic][$key]);\n                        }\n                    }\n                }\n            }\n\n            if (isset($options['order'])) {\n                // 视图查询排序处理\n                if (is_string($options['order'])) {\n                    $options['order'] = explode(',', $options['order']);\n                }\n                foreach ($options['order'] as $key => $val) {\n                    if (is_numeric($key)) {\n                        if (strpos($val, ' ')) {\n                            list($field, $sort) = explode(' ', $val);\n                            if (array_key_exists($field, $options['map'])) {\n                                $options['order'][$options['map'][$field]] = $sort;\n                                unset($options['order'][$key]);\n                            }\n                        } elseif (array_key_exists($val, $options['map'])) {\n                            $options['order'][$options['map'][$val]] = 'asc';\n                            unset($options['order'][$key]);\n                        }\n                    } elseif (array_key_exists($key, $options['map'])) {\n                        $options['order'][$options['map'][$key]] = $val;\n                        unset($options['order'][$key]);\n                    }\n                }\n            }\n        }\n\n        if (!isset($options['field'])) {\n            $options['field'] = '*';\n        }\n\n        if (!isset($options['data'])) {\n            $options['data'] = [];\n        }\n\n        if (!isset($options['strict'])) {\n            $options['strict'] = $this->getConfig('fields_strict');\n        }\n\n        foreach (['master', 'lock', 'fetch_pdo', 'fetch_sql', 'distinct'] as $name) {\n            if (!isset($options[$name])) {\n                $options[$name] = false;\n            }\n        }\n\n        foreach (['join', 'union', 'group', 'having', 'limit', 'order', 'force', 'comment'] as $name) {\n            if (!isset($options[$name])) {\n                $options[$name] = '';\n            }\n        }\n\n        if (isset($options['page'])) {\n            // 根据页数计算limit\n            list($page, $listRows) = $options['page'];\n            $page                  = $page > 0 ? $page : 1;\n            $listRows              = $listRows > 0 ? $listRows : (is_numeric($options['limit']) ? $options['limit'] : 20);\n            $offset                = $listRows * ($page - 1);\n            $options['limit']      = $offset . ',' . $listRows;\n        }\n\n        $this->options = [];\n        return $options;\n    }\n\n    /**\n     * 注册回调方法\n     * @access public\n     * @param string   $event    事件名\n     * @param callable $callback 回调方法\n     * @return void\n     */\n    public static function event($event, $callback)\n    {\n        self::$event[$event] = $callback;\n    }\n\n    /**\n     * 触发事件\n     * @access protected\n     * @param string $event   事件名\n     * @param mixed  $params  额外参数\n     * @return bool\n     */\n    protected function trigger($event, $params = [])\n    {\n        $result = false;\n        if (isset(self::$event[$event])) {\n            $callback = self::$event[$event];\n            $result   = call_user_func_array($callback, [$params, $this]);\n        }\n        return $result;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/builder/Mysql.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\builder;\n\nuse think\\db\\Builder;\n\n/**\n * mysql数据库驱动\n */\nclass Mysql extends Builder\n{\n    protected $updateSql = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';\n\n    /**\n     * 字段和表名处理\n     * @access protected\n     * @param string $key\n     * @param array  $options\n     * @return string\n     */\n    protected function parseKey($key, $options = [])\n    {\n        $key = trim($key);\n        if (strpos($key, '$.') && false === strpos($key, '(')) {\n            // JSON字段支持\n            list($field, $name) = explode('$.', $key);\n            $key                = 'json_extract(' . $field . ', \\'$.' . $name . '\\')';\n        } elseif (strpos($key, '.') && !preg_match('/[,\\'\\\"\\(\\)`\\s]/', $key)) {\n            list($table, $key) = explode('.', $key, 2);\n            if ('__TABLE__' == $table) {\n                $table = $this->query->getTable();\n            }\n            if (isset($options['alias'][$table])) {\n                $table = $options['alias'][$table];\n            }\n        }\n        if (!preg_match('/[,\\'\\\"\\*\\(\\)`.\\s]/', $key)) {\n            $key = '`' . $key . '`';\n        }\n        if (isset($table)) {\n            if (strpos($table, '.')) {\n                $table = str_replace('.', '`.`', $table);\n            }\n            $key = '`' . $table . '`.' . $key;\n        }\n        return $key;\n    }\n\n    /**\n     * 随机排序\n     * @access protected\n     * @return string\n     */\n    protected function parseRand()\n    {\n        return 'rand()';\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/builder/Pgsql.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\builder;\n\nuse think\\db\\Builder;\n\n/**\n * Pgsql数据库驱动\n */\nclass Pgsql extends Builder\n{\n\n    /**\n     * limit分析\n     * @access protected\n     * @param mixed $limit\n     * @return string\n     */\n    public function parseLimit($limit)\n    {\n        $limitStr = '';\n        if (!empty($limit)) {\n            $limit = explode(',', $limit);\n            if (count($limit) > 1) {\n                $limitStr .= ' LIMIT ' . $limit[1] . ' OFFSET ' . $limit[0] . ' ';\n            } else {\n                $limitStr .= ' LIMIT ' . $limit[0] . ' ';\n            }\n        }\n        return $limitStr;\n    }\n\n    /**\n     * 字段和表名处理\n     * @access protected\n     * @param string $key\n     * @param array  $options\n     * @return string\n     */\n    protected function parseKey($key, $options = [])\n    {\n        $key = trim($key);\n        if (strpos($key, '$.') && false === strpos($key, '(')) {\n            // JSON字段支持\n            list($field, $name) = explode('$.', $key);\n            $key                = $field . '->>\\'' . $name . '\\'';\n        } elseif (strpos($key, '.')) {\n            list($table, $key) = explode('.', $key, 2);\n            if ('__TABLE__' == $table) {\n                $table = $this->query->getTable();\n            }\n            if (isset($options['alias'][$table])) {\n                $table = $options['alias'][$table];\n            }\n        }\n        if (isset($table)) {\n            $key = $table . '.' . $key;\n        }\n        return $key;\n    }\n\n    /**\n     * 随机排序\n     * @access protected\n     * @return string\n     */\n    protected function parseRand()\n    {\n        return 'RANDOM()';\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/builder/Sqlite.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\builder;\n\nuse think\\db\\Builder;\n\n/**\n * Sqlite数据库驱动\n */\nclass Sqlite extends Builder\n{\n\n    /**\n     * limit\n     * @access public\n     * @return string\n     */\n    public function parseLimit($limit)\n    {\n        $limitStr = '';\n        if (!empty($limit)) {\n            $limit = explode(',', $limit);\n            if (count($limit) > 1) {\n                $limitStr .= ' LIMIT ' . $limit[1] . ' OFFSET ' . $limit[0] . ' ';\n            } else {\n                $limitStr .= ' LIMIT ' . $limit[0] . ' ';\n            }\n        }\n        return $limitStr;\n    }\n\n    /**\n     * 随机排序\n     * @access protected\n     * @return string\n     */\n    protected function parseRand()\n    {\n        return 'RANDOM()';\n    }\n\n    /**\n     * 字段和表名处理\n     * @access protected\n     * @param string $key\n     * @param array  $options\n     * @return string\n     */\n    protected function parseKey($key, $options = [])\n    {\n        $key = trim($key);\n        if (strpos($key, '.')) {\n            list($table, $key) = explode('.', $key, 2);\n            if ('__TABLE__' == $table) {\n                $table = $this->query->getTable();\n            }\n            if (isset($options['alias'][$table])) {\n                $table = $options['alias'][$table];\n            }\n        }\n        if (isset($table)) {\n            $key = $table . '.' . $key;\n        }\n        return $key;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/builder/Sqlsrv.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\builder;\n\nuse think\\db\\Builder;\n\n/**\n * Sqlsrv数据库驱动\n */\nclass Sqlsrv extends Builder\n{\n    protected $selectSql       = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%';\n    protected $selectInsertSql = 'SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%';\n    protected $updateSql       = 'UPDATE %TABLE% SET %SET% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';\n    protected $deleteSql       = 'DELETE FROM %TABLE%  %USING% FROM %TABLE%  %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';\n\n    /**\n     * order分析\n     * @access protected\n     * @param mixed $order\n     * @param array $options\n     * @return string\n     */\n    protected function parseOrder($order, $options = [])\n    {\n        if (is_array($order)) {\n            $array = [];\n            foreach ($order as $key => $val) {\n                if (is_numeric($key)) {\n                    if (false === strpos($val, '(')) {\n                        $array[] = $this->parseKey($val, $options);\n                    } elseif ('[rand]' == $val) {\n                        $array[] = $this->parseRand();\n                    }\n                } else {\n                    $sort    = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : '';\n                    $array[] = $this->parseKey($key, $options) . ' ' . $sort;\n                }\n            }\n            $order = implode(',', $array);\n        }\n        return !empty($order) ? ' ORDER BY ' . $order : ' ORDER BY rand()';\n    }\n\n    /**\n     * 随机排序\n     * @access protected\n     * @return string\n     */\n    protected function parseRand()\n    {\n        return 'rand()';\n    }\n\n    /**\n     * 字段和表名处理\n     * @access protected\n     * @param string $key\n     * @param array  $options\n     * @return string\n     */\n    protected function parseKey($key, $options = [])\n    {\n        $key = trim($key);\n        if (strpos($key, '.') && !preg_match('/[,\\'\\\"\\(\\)\\[\\s]/', $key)) {\n            list($table, $key) = explode('.', $key, 2);\n            if ('__TABLE__' == $table) {\n                $table = $this->query->getTable();\n            }\n            if (isset($options['alias'][$table])) {\n                $table = $options['alias'][$table];\n            }\n        }\n        if (!is_numeric($key) && !preg_match('/[,\\'\\\"\\*\\(\\)\\[.\\s]/', $key)) {\n            $key = '[' . $key . ']';\n        }\n        if (isset($table)) {\n            $key = '[' . $table . '].' . $key;\n        }\n        return $key;\n    }\n\n    /**\n     * limit\n     * @access protected\n     * @param mixed $limit\n     * @return string\n     */\n    protected function parseLimit($limit)\n    {\n        if (empty($limit)) {\n            return '';\n        }\n\n        $limit = explode(',', $limit);\n        if (count($limit) > 1) {\n            $limitStr = '(T1.ROW_NUMBER BETWEEN ' . $limit[0] . ' + 1 AND ' . $limit[0] . ' + ' . $limit[1] . ')';\n        } else {\n            $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND ' . $limit[0] . \")\";\n        }\n        return 'WHERE ' . $limitStr;\n    }\n\n    public function selectInsert($fields, $table, $options)\n    {\n        $this->selectSql = $this->selectInsertSql;\n        return parent::selectInsert($fields, $table, $options);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/connector/Mysql.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\connector;\n\nuse PDO;\nuse think\\db\\Connection;\nuse think\\Log;\n\n/**\n * mysql数据库驱动\n */\nclass Mysql extends Connection\n{\n\n    protected $builder = '\\\\think\\\\db\\\\builder\\\\Mysql';\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access protected\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {\n        $dsn = 'mysql:dbname=' . $config['database'] . ';host=' . $config['hostname'];\n        if (!empty($config['hostport'])) {\n            $dsn .= ';port=' . $config['hostport'];\n        } elseif (!empty($config['socket'])) {\n            $dsn .= ';unix_socket=' . $config['socket'];\n        }\n        if (!empty($config['charset'])) {\n            $dsn .= ';charset=' . $config['charset'];\n        }\n        return $dsn;\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @param string $tableName\n     * @return array\n     */\n    public function getFields($tableName)\n    {\n        list($tableName) = explode(' ', $tableName);\n        if (false === strpos($tableName, '`')) {\n            if (strpos($tableName, '.')) {\n                $tableName = str_replace('.', '`.`', $tableName);\n            }\n            $tableName = '`' . $tableName . '`';\n        }\n        $sql    = 'SHOW COLUMNS FROM ' . $tableName;\n        $pdo    = $this->query($sql, [], false, true);\n        $result = $pdo->fetchAll(PDO::FETCH_ASSOC);\n        $info   = [];\n        if ($result) {\n            foreach ($result as $key => $val) {\n                $val                 = array_change_key_case($val);\n                $info[$val['field']] = [\n                    'name'    => $val['field'],\n                    'type'    => $val['type'],\n                    'notnull' => (bool) ('' === $val['null']), // not null is empty, null is yes\n                    'default' => $val['default'],\n                    'primary' => (strtolower($val['key']) == 'pri'),\n                    'autoinc' => (strtolower($val['extra']) == 'auto_increment'),\n                ];\n            }\n        }\n        return $this->fieldCase($info);\n    }\n\n    /**\n     * 取得数据库的表信息\n     * @access public\n     * @param string $dbName\n     * @return array\n     */\n    public function getTables($dbName = '')\n    {\n        $sql    = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES ';\n        $pdo    = $this->query($sql, [], false, true);\n        $result = $pdo->fetchAll(PDO::FETCH_ASSOC);\n        $info   = [];\n        foreach ($result as $key => $val) {\n            $info[$key] = current($val);\n        }\n        return $info;\n    }\n\n    /**\n     * SQL性能分析\n     * @access protected\n     * @param string $sql\n     * @return array\n     */\n    protected function getExplain($sql)\n    {\n        $pdo    = $this->linkID->query(\"EXPLAIN \" . $sql);\n        $result = $pdo->fetch(PDO::FETCH_ASSOC);\n        $result = array_change_key_case($result);\n        if (isset($result['extra'])) {\n            if (strpos($result['extra'], 'filesort') || strpos($result['extra'], 'temporary')) {\n                Log::record('SQL:' . $this->queryStr . '[' . $result['extra'] . ']', 'warn');\n            }\n        }\n        return $result;\n    }\n\n    protected function supportSavepoint()\n    {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/connector/Pgsql.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\connector;\n\nuse PDO;\nuse think\\db\\Connection;\n\n/**\n * Pgsql数据库驱动\n */\nclass Pgsql extends Connection\n{\n    protected $builder = '\\\\think\\\\db\\\\builder\\\\Pgsql';\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access protected\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {\n        $dsn = 'pgsql:dbname=' . $config['database'] . ';host=' . $config['hostname'];\n        if (!empty($config['hostport'])) {\n            $dsn .= ';port=' . $config['hostport'];\n        }\n        return $dsn;\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @param string $tableName\n     * @return array\n     */\n    public function getFields($tableName)\n    {\n\n        list($tableName) = explode(' ', $tableName);\n        $sql             = 'select fields_name as \"field\",fields_type as \"type\",fields_not_null as \"null\",fields_key_name as \"key\",fields_default as \"default\",fields_default as \"extra\" from table_msg(\\'' . $tableName . '\\');';\n\n        $pdo    = $this->query($sql, [], false, true);\n        $result = $pdo->fetchAll(PDO::FETCH_ASSOC);\n        $info   = [];\n        if ($result) {\n            foreach ($result as $key => $val) {\n                $val                 = array_change_key_case($val);\n                $info[$val['field']] = [\n                    'name'    => $val['field'],\n                    'type'    => $val['type'],\n                    'notnull' => (bool) ('' !== $val['null']),\n                    'default' => $val['default'],\n                    'primary' => !empty($val['key']),\n                    'autoinc' => (0 === strpos($val['extra'], 'nextval(')),\n                ];\n            }\n        }\n        return $this->fieldCase($info);\n    }\n\n    /**\n     * 取得数据库的表信息\n     * @access public\n     * @param string $dbName\n     * @return array\n     */\n    public function getTables($dbName = '')\n    {\n        $sql    = \"select tablename as Tables_in_test from pg_tables where  schemaname ='public'\";\n        $pdo    = $this->query($sql, [], false, true);\n        $result = $pdo->fetchAll(PDO::FETCH_ASSOC);\n        $info   = [];\n        foreach ($result as $key => $val) {\n            $info[$key] = current($val);\n        }\n        return $info;\n    }\n\n    /**\n     * SQL性能分析\n     * @access protected\n     * @param string $sql\n     * @return array\n     */\n    protected function getExplain($sql)\n    {\n        return [];\n    }\n\n    protected function supportSavepoint()\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/connector/Sqlite.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\connector;\n\nuse PDO;\nuse think\\db\\Connection;\n\n/**\n * Sqlite数据库驱动\n */\nclass Sqlite extends Connection\n{\n\n    protected $builder = '\\\\think\\\\db\\\\builder\\\\Sqlite';\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access protected\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {\n        $dsn = 'sqlite:' . $config['database'];\n        return $dsn;\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @param string $tableName\n     * @return array\n     */\n    public function getFields($tableName)\n    {\n        list($tableName) = explode(' ', $tableName);\n        $sql             = 'PRAGMA table_info( ' . $tableName . ' )';\n\n        $pdo    = $this->query($sql, [], false, true);\n        $result = $pdo->fetchAll(PDO::FETCH_ASSOC);\n        $info   = [];\n        if ($result) {\n            foreach ($result as $key => $val) {\n                $val                = array_change_key_case($val);\n                $info[$val['name']] = [\n                    'name'    => $val['name'],\n                    'type'    => $val['type'],\n                    'notnull' => 1 === $val['notnull'],\n                    'default' => $val['dflt_value'],\n                    'primary' => '1' == $val['pk'],\n                    'autoinc' => '1' == $val['pk'],\n                ];\n            }\n        }\n        return $this->fieldCase($info);\n    }\n\n    /**\n     * 取得数据库的表信息\n     * @access public\n     * @param string $dbName\n     * @return array\n     */\n    public function getTables($dbName = '')\n    {\n\n        $sql = \"SELECT name FROM sqlite_master WHERE type='table' \"\n            . \"UNION ALL SELECT name FROM sqlite_temp_master \"\n            . \"WHERE type='table' ORDER BY name\";\n\n        $pdo    = $this->query($sql, [], false, true);\n        $result = $pdo->fetchAll(PDO::FETCH_ASSOC);\n        $info   = [];\n        foreach ($result as $key => $val) {\n            $info[$key] = current($val);\n        }\n        return $info;\n    }\n\n    /**\n     * SQL性能分析\n     * @access protected\n     * @param string $sql\n     * @return array\n     */\n    protected function getExplain($sql)\n    {\n        return [];\n    }\n\n    protected function supportSavepoint()\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/connector/Sqlsrv.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\connector;\n\nuse PDO;\nuse think\\db\\Connection;\n\n/**\n * Sqlsrv数据库驱动\n */\nclass Sqlsrv extends Connection\n{\n    // PDO连接参数\n    protected $params = [\n        PDO::ATTR_CASE              => PDO::CASE_NATURAL,\n        PDO::ATTR_ERRMODE           => PDO::ERRMODE_EXCEPTION,\n        PDO::ATTR_STRINGIFY_FETCHES => false,\n    ];\n    protected $builder = '\\\\think\\\\db\\\\builder\\\\Sqlsrv';\n    /**\n     * 解析pdo连接的dsn信息\n     * @access protected\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {\n        $dsn = 'sqlsrv:Database=' . $config['database'] . ';Server=' . $config['hostname'];\n        if (!empty($config['hostport'])) {\n            $dsn .= ',' . $config['hostport'];\n        }\n        return $dsn;\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @param string $tableName\n     * @return array\n     */\n    public function getFields($tableName)\n    {\n        list($tableName) = explode(' ', $tableName);\n        $sql             = \"SELECT   column_name,   data_type,   column_default,   is_nullable\n        FROM    information_schema.tables AS t\n        JOIN    information_schema.columns AS c\n        ON  t.table_catalog = c.table_catalog\n        AND t.table_schema  = c.table_schema\n        AND t.table_name    = c.table_name\n        WHERE   t.table_name = '$tableName'\";\n\n        $pdo    = $this->query($sql, [], false, true);\n        $result = $pdo->fetchAll(PDO::FETCH_ASSOC);\n        $info   = [];\n        if ($result) {\n            foreach ($result as $key => $val) {\n                $val                       = array_change_key_case($val);\n                $info[$val['column_name']] = [\n                    'name'    => $val['column_name'],\n                    'type'    => $val['data_type'],\n                    'notnull' => (bool) ('' === $val['is_nullable']), // not null is empty, null is yes\n                    'default' => $val['column_default'],\n                    'primary' => false,\n                    'autoinc' => false,\n                ];\n            }\n        }\n        $sql = \"SELECT column_name FROM information_schema.key_column_usage WHERE table_name='$tableName'\";\n        // 调试开始\n        $this->debug(true);\n        $pdo = $this->linkID->query($sql);\n        // 调试结束\n        $this->debug(false, $sql);\n        $result = $pdo->fetch(PDO::FETCH_ASSOC);\n        if ($result) {\n            $info[$result['column_name']]['primary'] = true;\n        }\n        return $this->fieldCase($info);\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @param string $dbName\n     * @return array\n     */\n    public function getTables($dbName = '')\n    {\n        $sql = \"SELECT TABLE_NAME\n            FROM INFORMATION_SCHEMA.TABLES\n            WHERE TABLE_TYPE = 'BASE TABLE'\n            \";\n\n        $pdo    = $this->query($sql, [], false, true);\n        $result = $pdo->fetchAll(PDO::FETCH_ASSOC);\n        $info   = [];\n        foreach ($result as $key => $val) {\n            $info[$key] = current($val);\n        }\n        return $info;\n    }\n\n    /**\n     * SQL性能分析\n     * @access protected\n     * @param string $sql\n     * @return array\n     */\n    protected function getExplain($sql)\n    {\n        return [];\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/connector/pgsql.sql",
    "content": "CREATE OR REPLACE FUNCTION pgsql_type(a_type varchar) RETURNS varchar AS\n$BODY$\nDECLARE\n     v_type varchar;\nBEGIN\n     IF a_type='int8' THEN\n          v_type:='bigint';\n     ELSIF a_type='int4' THEN\n          v_type:='integer';\n     ELSIF a_type='int2' THEN\n          v_type:='smallint';\n     ELSIF a_type='bpchar' THEN\n          v_type:='char';\n     ELSE\n          v_type:=a_type;\n     END IF;\n     RETURN v_type;\nEND;\n$BODY$\nLANGUAGE PLPGSQL;\n\nCREATE TYPE \"public\".\"tablestruct\" AS (\n  \"fields_key_name\" varchar(100),\n  \"fields_name\" VARCHAR(200),\n  \"fields_type\" VARCHAR(20),\n  \"fields_length\" BIGINT,\n  \"fields_not_null\" VARCHAR(10),\n  \"fields_default\" VARCHAR(500),\n  \"fields_comment\" VARCHAR(1000)\n);\n\nCREATE OR REPLACE FUNCTION \"public\".\"table_msg\" (a_schema_name varchar, a_table_name varchar) RETURNS SETOF \"public\".\"tablestruct\" AS\n$body$\nDECLARE\n     v_ret tablestruct;\n     v_oid oid;\n     v_sql varchar;\n     v_rec RECORD;\n     v_key varchar;\nBEGIN\n     SELECT\n           pg_class.oid  INTO v_oid\n     FROM\n           pg_class\n           INNER JOIN pg_namespace ON (pg_class.relnamespace = pg_namespace.oid AND lower(pg_namespace.nspname) = a_schema_name)\n     WHERE\n           pg_class.relname=a_table_name;\n     IF NOT FOUND THEN\n         RETURN;\n     END IF;\n\n     v_sql='\n     SELECT\n           pg_attribute.attname AS fields_name,\n           pg_attribute.attnum AS fields_index,\n           pgsql_type(pg_type.typname::varchar) AS fields_type,\n           pg_attribute.atttypmod-4 as fields_length,\n           CASE WHEN pg_attribute.attnotnull  THEN ''not null''\n           ELSE ''''\n           END AS fields_not_null,\n           pg_attrdef.adsrc AS fields_default,\n           pg_description.description AS fields_comment\n     FROM\n           pg_attribute\n           INNER JOIN pg_class  ON pg_attribute.attrelid = pg_class.oid\n           INNER JOIN pg_type   ON pg_attribute.atttypid = pg_type.oid\n           LEFT OUTER JOIN pg_attrdef ON pg_attrdef.adrelid = pg_class.oid AND pg_attrdef.adnum = pg_attribute.attnum\n           LEFT OUTER JOIN pg_description ON pg_description.objoid = pg_class.oid AND pg_description.objsubid = pg_attribute.attnum\n     WHERE\n           pg_attribute.attnum > 0\n           AND attisdropped <> ''t''\n           AND pg_class.oid = ' || v_oid || '\n     ORDER BY pg_attribute.attnum' ;\n\n     FOR v_rec IN EXECUTE v_sql LOOP\n         v_ret.fields_name=v_rec.fields_name;\n         v_ret.fields_type=v_rec.fields_type;\n         IF v_rec.fields_length > 0 THEN\n            v_ret.fields_length:=v_rec.fields_length;\n         ELSE\n            v_ret.fields_length:=NULL;\n         END IF;\n         v_ret.fields_not_null=v_rec.fields_not_null;\n         v_ret.fields_default=v_rec.fields_default;\n         v_ret.fields_comment=v_rec.fields_comment;\n         SELECT constraint_name INTO v_key FROM information_schema.key_column_usage WHERE table_schema=a_schema_name AND table_name=a_table_name AND column_name=v_rec.fields_name;\n         IF FOUND THEN\n            v_ret.fields_key_name=v_key;\n         ELSE\n            v_ret.fields_key_name='';\n         END IF;\n         RETURN NEXT v_ret;\n     END LOOP;\n     RETURN ;\nEND;\n$body$\nLANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;\n\nCOMMENT ON FUNCTION \"public\".\"table_msg\"(a_schema_name varchar, a_table_name varchar)\nIS '获得表信息';\n\n---重载一个函数\nCREATE OR REPLACE FUNCTION \"public\".\"table_msg\" (a_table_name varchar) RETURNS SETOF \"public\".\"tablestruct\" AS\n$body$\nDECLARE\n    v_ret tablestruct;\nBEGIN\n    FOR v_ret IN SELECT * FROM table_msg('public',a_table_name) LOOP\n        RETURN NEXT v_ret;\n    END LOOP;\n    RETURN;\nEND;\n$body$\nLANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;\n\nCOMMENT ON FUNCTION \"public\".\"table_msg\"(a_table_name varchar)\nIS '获得表信息';"
  },
  {
    "path": "thinkphp/library/think/db/exception/BindParamException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\exception;\n\nuse think\\exception\\DbException;\n\n/**\n * PDO参数绑定异常\n */\nclass BindParamException extends DbException\n{\n\n    /**\n     * BindParamException constructor.\n     * @param string $message\n     * @param array  $config\n     * @param string $sql\n     * @param array    $bind\n     * @param int    $code\n     */\n    public function __construct($message, $config, $sql, $bind, $code = 10502)\n    {\n        $this->setData('Bind Param', $bind);\n        parent::__construct($message, $config, $sql, $code);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/exception/DataNotFoundException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\exception;\n\nuse think\\exception\\DbException;\n\nclass DataNotFoundException extends DbException\n{\n    protected $table;\n\n    /**\n     * DbException constructor.\n     * @param string $message\n     * @param string $table\n     * @param array $config\n     */\n    public function __construct($message, $table = '', array $config = [])\n    {\n        $this->message = $message;\n        $this->table   = $table;\n\n        $this->setData('Database Config', $config);\n    }\n\n    /**\n     * 获取数据表名\n     * @access public\n     * @return string\n     */\n    public function getTable()\n    {\n        return $this->table;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/db/exception/ModelNotFoundException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace think\\db\\exception;\n\nuse think\\exception\\DbException;\n\nclass ModelNotFoundException extends DbException\n{\n    protected $model;\n\n    /**\n     * 构造方法\n     * @param string $message\n     * @param string $model\n     */\n    public function __construct($message, $model = '', array $config = [])\n    {\n        $this->message = $message;\n        $this->model   = $model;\n\n        $this->setData('Database Config', $config);\n    }\n\n    /**\n     * 获取模型类名\n     * @access public\n     * @return string\n     */\n    public function getModel()\n    {\n        return $this->model;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/debug/Console.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yangweijie <yangweijiester@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\debug;\n\nuse think\\Cache;\nuse think\\Config;\nuse think\\Db;\nuse think\\Debug;\nuse think\\Request;\nuse think\\Response;\n\n/**\n * 浏览器调试输出\n */\nclass Console\n{\n    protected $config = [\n        'trace_tabs' => ['base' => '基本', 'file' => '文件', 'info' => '流程', 'notice|error' => '错误', 'sql' => 'SQL', 'debug|log' => '调试'],\n    ];\n\n    // 实例化并传入参数\n    public function __construct($config = [])\n    {\n        if (is_array($config)) {\n            $this->config = array_merge($this->config, $config);\n        }\n    }\n\n    /**\n     * 调试输出接口\n     * @access public\n     * @param Response  $response Response对象\n     * @param array     $log 日志信息\n     * @return bool\n     */\n    public function output(Response $response, array $log = [])\n    {\n        $request     = Request::instance();\n        $contentType = $response->getHeader('Content-Type');\n        $accept      = $request->header('accept');\n        if (strpos($accept, 'application/json') === 0 || $request->isAjax()) {\n            return false;\n        } elseif (!empty($contentType) && strpos($contentType, 'html') === false) {\n            return false;\n        }\n        // 获取基本信息\n        $runtime = number_format(microtime(true) - THINK_START_TIME, 10);\n        $reqs    = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';\n        $mem     = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);\n\n        if (isset($_SERVER['HTTP_HOST'])) {\n            $uri = $_SERVER['SERVER_PROTOCOL'] . ' ' . $_SERVER['REQUEST_METHOD'] . ' : ' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];\n        } else {\n            $uri = 'cmd:' . implode(' ', $_SERVER['argv']);\n        }\n\n        // 页面Trace信息\n        $base = [\n            '请求信息' => date('Y-m-d H:i:s', $_SERVER['REQUEST_TIME']) . ' ' . $uri,\n            '运行时间' => number_format($runtime, 6) . 's [ 吞吐率：' . $reqs . 'req/s ] 内存消耗：' . $mem . 'kb 文件加载：' . count(get_included_files()),\n            '查询信息' => Db::$queryTimes . ' queries ' . Db::$executeTimes . ' writes ',\n            '缓存信息' => Cache::$readTimes . ' reads,' . Cache::$writeTimes . ' writes',\n            '配置加载' => count(Config::get()),\n        ];\n\n        if (session_id()) {\n            $base['会话信息'] = 'SESSION_ID=' . session_id();\n        }\n\n        $info = Debug::getFile(true);\n\n        // 页面Trace信息\n        $trace = [];\n        foreach ($this->config['trace_tabs'] as $name => $title) {\n            $name = strtolower($name);\n            switch ($name) {\n                case 'base': // 基本信息\n                    $trace[$title] = $base;\n                    break;\n                case 'file': // 文件信息\n                    $trace[$title] = $info;\n                    break;\n                default: // 调试信息\n                    if (strpos($name, '|')) {\n                        // 多组信息\n                        $names  = explode('|', $name);\n                        $result = [];\n                        foreach ($names as $name) {\n                            $result = array_merge($result, isset($log[$name]) ? $log[$name] : []);\n                        }\n                        $trace[$title] = $result;\n                    } else {\n                        $trace[$title] = isset($log[$name]) ? $log[$name] : '';\n                    }\n            }\n        }\n\n        //输出到控制台\n        $lines = '';\n        foreach ($trace as $type => $msg) {\n            $lines .= $this->console($type, $msg);\n        }\n        $js = <<<JS\n\n<script type='text/javascript'>\n{$lines}\n</script>\nJS;\n        return $js;\n    }\n\n    protected function console($type, $msg)\n    {\n        $type       = strtolower($type);\n        $trace_tabs = array_values($this->config['trace_tabs']);\n        $line[]     = ($type == $trace_tabs[0] || '调试' == $type || '错误' == $type)\n        ? \"console.group('{$type}');\"\n        : \"console.groupCollapsed('{$type}');\";\n\n        foreach ((array) $msg as $key => $m) {\n            switch ($type) {\n                case '调试':\n                    $var_type = gettype($m);\n                    if (in_array($var_type, ['array', 'string'])) {\n                        $line[] = \"console.log(\" . json_encode($m) . \");\";\n                    } else {\n                        $line[] = \"console.log(\" . json_encode(var_export($m, 1)) . \");\";\n                    }\n                    break;\n                case '错误':\n                    $msg    = str_replace(\"\\n\", '\\n', $m);\n                    $style  = 'color:#F4006B;font-size:14px;';\n                    $line[] = \"console.error(\\\"%c{$msg}\\\", \\\"{$style}\\\");\";\n                    break;\n                case 'sql':\n                    $msg    = str_replace(\"\\n\", '\\n', $m);\n                    $style  = \"color:#009bb4;\";\n                    $line[] = \"console.log(\\\"%c{$msg}\\\", \\\"{$style}\\\");\";\n                    break;\n                default:\n                    $m      = is_string($key) ? $key . ' ' . $m : $key + 1 . ' ' . $m;\n                    $msg    = json_encode($m);\n                    $line[] = \"console.log({$msg});\";\n                    break;\n            }\n        }\n        $line[] = \"console.groupEnd();\";\n        return implode(PHP_EOL, $line);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/debug/Html.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\debug;\n\nuse think\\Cache;\nuse think\\Config;\nuse think\\Db;\nuse think\\Debug;\nuse think\\Request;\nuse think\\Response;\n\n/**\n * 页面Trace调试\n */\nclass Html\n{\n    protected $config = [\n        'trace_file' => '',\n        'trace_tabs' => ['base' => '基本', 'file' => '文件', 'info' => '流程', 'notice|error' => '错误', 'sql' => 'SQL', 'debug|log' => '调试'],\n    ];\n\n    // 实例化并传入参数\n    public function __construct(array $config = [])\n    {\n        $this->config['trace_file'] = THINK_PATH . 'tpl/page_trace.tpl';\n        $this->config               = array_merge($this->config, $config);\n    }\n\n    /**\n     * 调试输出接口\n     * @access public\n     * @param Response  $response Response对象\n     * @param array     $log 日志信息\n     * @return bool\n     */\n    public function output(Response $response, array $log = [])\n    {\n        $request     = Request::instance();\n        $contentType = $response->getHeader('Content-Type');\n        $accept      = $request->header('accept');\n        if (strpos($accept, 'application/json') === 0 || $request->isAjax()) {\n            return false;\n        } elseif (!empty($contentType) && strpos($contentType, 'html') === false) {\n            return false;\n        }\n        // 获取基本信息\n        $runtime = number_format(microtime(true) - THINK_START_TIME, 10);\n        $reqs    = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';\n        $mem     = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);\n\n        // 页面Trace信息\n        if (isset($_SERVER['HTTP_HOST'])) {\n            $uri = $_SERVER['SERVER_PROTOCOL'] . ' ' . $_SERVER['REQUEST_METHOD'] . ' : ' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];\n        } else {\n            $uri = 'cmd:' . implode(' ', $_SERVER['argv']);\n        }\n        $base = [\n            '请求信息' => date('Y-m-d H:i:s', $_SERVER['REQUEST_TIME']) . ' ' . $uri,\n            '运行时间' => number_format($runtime, 6) . 's [ 吞吐率：' . $reqs . 'req/s ] 内存消耗：' . $mem . 'kb 文件加载：' . count(get_included_files()),\n            '查询信息' => Db::$queryTimes . ' queries ' . Db::$executeTimes . ' writes ',\n            '缓存信息' => Cache::$readTimes . ' reads,' . Cache::$writeTimes . ' writes',\n            '配置加载' => count(Config::get()),\n        ];\n\n        if (session_id()) {\n            $base['会话信息'] = 'SESSION_ID=' . session_id();\n        }\n\n        $info = Debug::getFile(true);\n\n        // 页面Trace信息\n        $trace = [];\n        foreach ($this->config['trace_tabs'] as $name => $title) {\n            $name = strtolower($name);\n            switch ($name) {\n                case 'base': // 基本信息\n                    $trace[$title] = $base;\n                    break;\n                case 'file': // 文件信息\n                    $trace[$title] = $info;\n                    break;\n                default: // 调试信息\n                    if (strpos($name, '|')) {\n                        // 多组信息\n                        $names  = explode('|', $name);\n                        $result = [];\n                        foreach ($names as $name) {\n                            $result = array_merge($result, isset($log[$name]) ? $log[$name] : []);\n                        }\n                        $trace[$title] = $result;\n                    } else {\n                        $trace[$title] = isset($log[$name]) ? $log[$name] : '';\n                    }\n            }\n        }\n        // 调用Trace页面模板\n        ob_start();\n        include $this->config['trace_file'];\n        return ob_get_clean();\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/ClassNotFoundException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\nclass ClassNotFoundException extends \\RuntimeException\n{\n    protected $class;\n    public function __construct($message, $class = '')\n    {\n        $this->message = $message;\n        $this->class   = $class;\n    }\n\n    /**\n     * 获取类名\n     * @access public\n     * @return string\n     */\n    public function getClass()\n    {\n        return $this->class;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/DbException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\nuse think\\Exception;\n\n/**\n * Database相关异常处理类\n */\nclass DbException extends Exception\n{\n    /**\n     * DbException constructor.\n     * @param string    $message\n     * @param array     $config\n     * @param string    $sql\n     * @param int       $code\n     */\n    public function __construct($message, array $config, $sql, $code = 10500)\n    {\n        $this->message = $message;\n        $this->code    = $code;\n\n        $this->setData('Database Status', [\n            'Error Code'    => $code,\n            'Error Message' => $message,\n            'Error SQL'     => $sql,\n        ]);\n\n        unset($config['username'], $config['password']);\n        $this->setData('Database Config', $config);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/ErrorException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\nuse think\\Exception;\n\n/**\n * ThinkPHP错误异常\n * 主要用于封装 set_error_handler 和 register_shutdown_function 得到的错误\n * 除开从 think\\Exception 继承的功能\n * 其他和PHP系统\\ErrorException功能基本一样\n */\nclass ErrorException extends Exception\n{\n    /**\n     * 用于保存错误级别\n     * @var integer\n     */\n    protected $severity;\n\n    /**\n     * 错误异常构造函数\n     * @param integer $severity 错误级别\n     * @param string  $message  错误详细信息\n     * @param string  $file     出错文件路径\n     * @param integer $line     出错行号\n     * @param array   $context  错误上下文，会包含错误触发处作用域内所有变量的数组\n     */\n    public function __construct($severity, $message, $file, $line, array $context = [])\n    {\n        $this->severity = $severity;\n        $this->message  = $message;\n        $this->file     = $file;\n        $this->line     = $line;\n        $this->code     = 0;\n\n        empty($context) || $this->setData('Error Context', $context);\n    }\n\n    /**\n     * 获取错误级别\n     * @return integer 错误级别\n     */\n    final public function getSeverity()\n    {\n        return $this->severity;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/Handle.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\nuse Exception;\nuse think\\App;\nuse think\\Config;\nuse think\\console\\Output;\nuse think\\Lang;\nuse think\\Log;\nuse think\\Response;\n\nclass Handle\n{\n\n    protected $ignoreReport = [\n        '\\\\think\\\\exception\\\\HttpException',\n    ];\n\n    /**\n     * Report or log an exception.\n     *\n     * @param  \\Exception $exception\n     * @return void\n     */\n    public function report(Exception $exception)\n    {\n        if (!$this->isIgnoreReport($exception)) {\n            // 收集异常数据\n            if (App::$debug) {\n                $data = [\n                    'file'    => $exception->getFile(),\n                    'line'    => $exception->getLine(),\n                    'message' => $this->getMessage($exception),\n                    'code'    => $this->getCode($exception),\n                ];\n                $log = \"[{$data['code']}]{$data['message']}[{$data['file']}:{$data['line']}]\";\n            } else {\n                $data = [\n                    'code'    => $this->getCode($exception),\n                    'message' => $this->getMessage($exception),\n                ];\n                $log = \"[{$data['code']}]{$data['message']}\";\n            }\n\n            if (Config::get('record_trace')) {\n                $log .= \"\\r\\n\" . $exception->getTraceAsString();\n            }\n\n            Log::record($log, 'error');\n        }\n    }\n\n    protected function isIgnoreReport(Exception $exception)\n    {\n        foreach ($this->ignoreReport as $class) {\n            if ($exception instanceof $class) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Render an exception into an HTTP response.\n     *\n     * @param  \\Exception $e\n     * @return Response\n     */\n    public function render(Exception $e)\n    {\n        if ($e instanceof HttpException) {\n            return $this->renderHttpException($e);\n        } else {\n            return $this->convertExceptionToResponse($e);\n        }\n    }\n\n    /**\n     * @param Output    $output\n     * @param Exception $e\n     */\n    public function renderForConsole(Output $output, Exception $e)\n    {\n        if (App::$debug) {\n            $output->setVerbosity(Output::VERBOSITY_DEBUG);\n        }\n        $output->renderException($e);\n    }\n\n    /**\n     * @param HttpException $e\n     * @return Response\n     */\n    protected function renderHttpException(HttpException $e)\n    {\n        $status   = $e->getStatusCode();\n        $template = Config::get('http_exception_template');\n        if (!App::$debug && !empty($template[$status])) {\n            return Response::create($template[$status], 'view', $status)->assign(['e' => $e]);\n        } else {\n            return $this->convertExceptionToResponse($e);\n        }\n    }\n\n    /**\n     * @param Exception $exception\n     * @return Response\n     */\n    protected function convertExceptionToResponse(Exception $exception)\n    {\n        // 收集异常数据\n        if (App::$debug) {\n            // 调试模式，获取详细的错误信息\n            $data = [\n                'name'    => get_class($exception),\n                'file'    => $exception->getFile(),\n                'line'    => $exception->getLine(),\n                'message' => $this->getMessage($exception),\n                'trace'   => $exception->getTrace(),\n                'code'    => $this->getCode($exception),\n                'source'  => $this->getSourceCode($exception),\n                'datas'   => $this->getExtendData($exception),\n                'tables'  => [\n                    'GET Data'              => $_GET,\n                    'POST Data'             => $_POST,\n                    'Files'                 => $_FILES,\n                    'Cookies'               => $_COOKIE,\n                    'Session'               => isset($_SESSION) ? $_SESSION : [],\n                    'Server/Request Data'   => $_SERVER,\n                    'Environment Variables' => $_ENV,\n                    'ThinkPHP Constants'    => $this->getConst(),\n                ],\n            ];\n        } else {\n            // 部署模式仅显示 Code 和 Message\n            $data = [\n                'code'    => $this->getCode($exception),\n                'message' => $this->getMessage($exception),\n            ];\n\n            if (!Config::get('show_error_msg')) {\n                // 不显示详细错误信息\n                $data['message'] = Config::get('error_message');\n            }\n        }\n\n        //保留一层\n        while (ob_get_level() > 1) {\n            ob_end_clean();\n        }\n\n        $data['echo'] = ob_get_clean();\n\n        ob_start();\n        extract($data);\n        include Config::get('exception_tmpl');\n        // 获取并清空缓存\n        $content  = ob_get_clean();\n        $response = new Response($content, 'html');\n\n        if ($exception instanceof HttpException) {\n            $statusCode = $exception->getStatusCode();\n            $response->header($exception->getHeaders());\n        }\n\n        if (!isset($statusCode)) {\n            $statusCode = 500;\n        }\n        $response->code($statusCode);\n        return $response;\n    }\n\n    /**\n     * 获取错误编码\n     * ErrorException则使用错误级别作为错误编码\n     * @param  \\Exception $exception\n     * @return integer                错误编码\n     */\n    protected function getCode(Exception $exception)\n    {\n        $code = $exception->getCode();\n        if (!$code && $exception instanceof ErrorException) {\n            $code = $exception->getSeverity();\n        }\n        return $code;\n    }\n\n    /**\n     * 获取错误信息\n     * ErrorException则使用错误级别作为错误编码\n     * @param  \\Exception $exception\n     * @return string                错误信息\n     */\n    protected function getMessage(Exception $exception)\n    {\n        $message = $exception->getMessage();\n        if (IS_CLI) {\n            return $message;\n        }\n\n        if (strpos($message, ':')) {\n            $name    = strstr($message, ':', true);\n            $message = Lang::has($name) ? Lang::get($name) . strstr($message, ':') : $message;\n        } elseif (strpos($message, ',')) {\n            $name    = strstr($message, ',', true);\n            $message = Lang::has($name) ? Lang::get($name) . ':' . substr(strstr($message, ','), 1) : $message;\n        } elseif (Lang::has($message)) {\n            $message = Lang::get($message);\n        }\n        return $message;\n    }\n\n    /**\n     * 获取出错文件内容\n     * 获取错误的前9行和后9行\n     * @param  \\Exception $exception\n     * @return array                 错误文件内容\n     */\n    protected function getSourceCode(Exception $exception)\n    {\n        // 读取前9行和后9行\n        $line  = $exception->getLine();\n        $first = ($line - 9 > 0) ? $line - 9 : 1;\n\n        try {\n            $contents = file($exception->getFile());\n            $source   = [\n                'first'  => $first,\n                'source' => array_slice($contents, $first - 1, 19),\n            ];\n        } catch (Exception $e) {\n            $source = [];\n        }\n        return $source;\n    }\n\n    /**\n     * 获取异常扩展信息\n     * 用于非调试模式html返回类型显示\n     * @param  \\Exception $exception\n     * @return array                 异常类定义的扩展数据\n     */\n    protected function getExtendData(Exception $exception)\n    {\n        $data = [];\n        if ($exception instanceof \\think\\Exception) {\n            $data = $exception->getData();\n        }\n        return $data;\n    }\n\n    /**\n     * 获取常量列表\n     * @return array 常量列表\n     */\n    private static function getConst()\n    {\n        return get_defined_constants(true)['user'];\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/HttpException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\nclass HttpException extends \\RuntimeException\n{\n    private $statusCode;\n    private $headers;\n\n    public function __construct($statusCode, $message = null, \\Exception $previous = null, array $headers = [], $code = 0)\n    {\n        $this->statusCode = $statusCode;\n        $this->headers    = $headers;\n\n        parent::__construct($message, $code, $previous);\n    }\n\n    public function getStatusCode()\n    {\n        return $this->statusCode;\n    }\n\n    public function getHeaders()\n    {\n        return $this->headers;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/HttpResponseException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\nuse think\\Response;\n\nclass HttpResponseException extends \\RuntimeException\n{\n    /**\n     * @var Response\n     */\n    protected $response;\n\n    public function __construct(Response $response)\n    {\n        $this->response = $response;\n    }\n\n    public function getResponse()\n    {\n        return $this->response;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/PDOException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\n/**\n * PDO异常处理类\n * 重新封装了系统的\\PDOException类\n */\nclass PDOException extends DbException\n{\n    /**\n     * PDOException constructor.\n     * @param \\PDOException $exception\n     * @param array         $config\n     * @param string        $sql\n     * @param int           $code\n     */\n    public function __construct(\\PDOException $exception, array $config, $sql, $code = 10501)\n    {\n        $error = $exception->errorInfo;\n\n        $this->setData('PDO Error Info', [\n            'SQLSTATE'             => $error[0],\n            'Driver Error Code'    => isset($error[1]) ? $error[1] : 0,\n            'Driver Error Message' => isset($error[2]) ? $error[2] : '',\n        ]);\n\n        parent::__construct($exception->getMessage(), $config, $sql, $code);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/RouteNotFoundException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\nclass RouteNotFoundException extends HttpException\n{\n\n    public function __construct()\n    {\n        parent::__construct(404);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/TemplateNotFoundException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\nclass TemplateNotFoundException extends \\RuntimeException\n{\n    protected $template;\n\n    public function __construct($message, $template = '')\n    {\n        $this->message  = $message;\n        $this->template = $template;\n    }\n\n    /**\n     * 获取模板文件\n     * @access public\n     * @return string\n     */\n    public function getTemplate()\n    {\n        return $this->template;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/ThrowableError.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\nclass ThrowableError extends \\ErrorException\n{\n    public function __construct(\\Throwable $e)\n    {\n\n        if ($e instanceof \\ParseError) {\n            $message  = 'Parse error: ' . $e->getMessage();\n            $severity = E_PARSE;\n        } elseif ($e instanceof \\TypeError) {\n            $message  = 'Type error: ' . $e->getMessage();\n            $severity = E_RECOVERABLE_ERROR;\n        } else {\n            $message  = 'Fatal error: ' . $e->getMessage();\n            $severity = E_ERROR;\n        }\n\n        parent::__construct(\n            $message,\n            $e->getCode(),\n            $severity,\n            $e->getFile(),\n            $e->getLine()\n        );\n\n        $this->setTrace($e->getTrace());\n    }\n\n    protected function setTrace($trace)\n    {\n        $traceReflector = new \\ReflectionProperty('Exception', 'trace');\n        $traceReflector->setAccessible(true);\n        $traceReflector->setValue($this, $trace);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/exception/ValidateException.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\exception;\n\nclass ValidateException extends \\RuntimeException\n{\n    protected $error;\n\n    public function __construct($error)\n    {\n        $this->error   = $error;\n        $this->message = is_array($error) ? implode(\"\\n\\r\", $error) : $error;\n    }\n\n    /**\n     * 获取验证错误信息\n     * @access public\n     * @return array|string\n     */\n    public function getError()\n    {\n        return $this->error;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/log/driver/File.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\log\\driver;\n\nuse think\\App;\n\n/**\n * 本地化调试输出到文件\n */\nclass File\n{\n    protected $config = [\n        'time_format' => ' c ',\n        'file_size'   => 2097152,\n        'path'        => LOG_PATH,\n        'apart_level' => [],\n    ];\n\n    protected $writed = [];\n\n    // 实例化并传入参数\n    public function __construct($config = [])\n    {\n        if (is_array($config)) {\n            $this->config = array_merge($this->config, $config);\n        }\n    }\n\n    /**\n     * 日志写入接口\n     * @access public\n     * @param array $log 日志信息\n     * @return bool\n     */\n    public function save(array $log = [])\n    {\n        $cli         = IS_CLI ? '_cli' : '';\n        $destination = $this->config['path'] . date('Ym') . DS . date('d') . $cli . '.log';\n\n        $path = dirname($destination);\n        !is_dir($path) && mkdir($path, 0755, true);\n\n        $info = '';\n        foreach ($log as $type => $val) {\n            $level = '';\n            foreach ($val as $msg) {\n                if (!is_string($msg)) {\n                    $msg = var_export($msg, true);\n                }\n                $level .= '[ ' . $type . ' ] ' . $msg . \"\\r\\n\";\n            }\n            if (in_array($type, $this->config['apart_level'])) {\n                // 独立记录的日志级别\n                $filename = $path . DS . date('d') . '_' . $type . $cli . '.log';\n                $this->write($level, $filename, true);\n            } else {\n                $info .= $level;\n            }\n        }\n        if ($info) {\n            return $this->write($info, $destination);\n        }\n        return true;\n    }\n\n    protected function write($message, $destination, $apart = false)\n    {\n        //检测日志文件大小，超过配置大小则备份日志文件重新生成\n        if (is_file($destination) && floor($this->config['file_size']) <= filesize($destination)) {\n            rename($destination, dirname($destination) . DS . time() . '-' . basename($destination));\n            $this->writed[$destination] = false;\n        }\n\n        if (empty($this->writed[$destination]) && !IS_CLI) {\n            if (App::$debug && !$apart) {\n                // 获取基本信息\n                if (isset($_SERVER['HTTP_HOST'])) {\n                    $current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];\n                } else {\n                    $current_uri = \"cmd:\" . implode(' ', $_SERVER['argv']);\n                }\n\n                $runtime    = round(microtime(true) - THINK_START_TIME, 10);\n                $reqs       = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';\n                $time_str   = ' [运行时间：' . number_format($runtime, 6) . 's][吞吐率：' . $reqs . 'req/s]';\n                $memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);\n                $memory_str = ' [内存消耗：' . $memory_use . 'kb]';\n                $file_load  = ' [文件加载：' . count(get_included_files()) . ']';\n\n                $message = '[ info ] ' . $current_uri . $time_str . $memory_str . $file_load . \"\\r\\n\" . $message;\n            }\n            $now     = date($this->config['time_format']);\n            $server  = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '0.0.0.0';\n            $remote  = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';\n            $method  = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'CLI';\n            $uri     = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';\n            $message = \"---------------------------------------------------------------\\r\\n[{$now}] {$server} {$remote} {$method} {$uri}\\r\\n\" . $message;\n\n            $this->writed[$destination] = true;\n        }\n\n        if (IS_CLI) {\n            $now     = date($this->config['time_format']);\n            $message = \"[{$now}]\" . $message;\n        }\n\n        return error_log($message, 3, $destination);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/log/driver/Socket.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: luofei614 <weibo.com/luofei614>\n// +----------------------------------------------------------------------\n\nnamespace think\\log\\driver;\n\nuse think\\App;\n\n/**\n * github: https://github.com/luofei614/SocketLog\n * @author luofei614<weibo.com/luofei614>\n */\nclass Socket\n{\n    public $port = 1116; //SocketLog 服务的http的端口号\n\n    protected $config = [\n        // socket服务器地址\n        'host'                => 'localhost',\n        // 是否显示加载的文件列表\n        'show_included_files' => false,\n        // 日志强制记录到配置的client_id\n        'force_client_ids'    => [],\n        // 限制允许读取日志的client_id\n        'allow_client_ids'    => [],\n    ];\n\n    protected $css = [\n        'sql'      => 'color:#009bb4;',\n        'sql_warn' => 'color:#009bb4;font-size:14px;',\n        'error'    => 'color:#f4006b;font-size:14px;',\n        'page'     => 'color:#40e2ff;background:#171717;',\n        'big'      => 'font-size:20px;color:red;',\n    ];\n\n    protected $allowForceClientIds = []; //配置强制推送且被授权的client_id\n\n    /**\n     * 构造函数\n     * @param array $config 缓存参数\n     * @access public\n     */\n    public function __construct(array $config = [])\n    {\n        if (!empty($config)) {\n            $this->config = array_merge($this->config, $config);\n        }\n    }\n\n    /**\n     * 调试输出接口\n     * @access public\n     * @param array     $log 日志信息\n     * @return bool\n     */\n    public function save(array $log = [])\n    {\n        if (!$this->check()) {\n            return false;\n        }\n        $trace = [];\n        if (App::$debug) {\n            $runtime    = round(microtime(true) - THINK_START_TIME, 10);\n            $reqs       = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';\n            $time_str   = ' [运行时间：' . number_format($runtime, 6) . 's][吞吐率：' . $reqs . 'req/s]';\n            $memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);\n            $memory_str = ' [内存消耗：' . $memory_use . 'kb]';\n            $file_load  = ' [文件加载：' . count(get_included_files()) . ']';\n\n            if (isset($_SERVER['HTTP_HOST'])) {\n                $current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];\n            } else {\n                $current_uri = 'cmd:' . implode(' ', $_SERVER['argv']);\n            }\n            // 基本信息\n            $trace[] = [\n                'type' => 'group',\n                'msg'  => $current_uri . $time_str . $memory_str . $file_load,\n                'css'  => $this->css['page'],\n            ];\n        }\n\n        foreach ($log as $type => $val) {\n            $trace[] = [\n                'type' => 'groupCollapsed',\n                'msg'  => '[ ' . $type . ' ]',\n                'css'  => isset($this->css[$type]) ? $this->css[$type] : '',\n            ];\n            foreach ($val as $msg) {\n                if (!is_string($msg)) {\n                    $msg = var_export($msg, true);\n                }\n                $trace[] = [\n                    'type' => 'log',\n                    'msg'  => $msg,\n                    'css'  => '',\n                ];\n            }\n            $trace[] = [\n                'type' => 'groupEnd',\n                'msg'  => '',\n                'css'  => '',\n            ];\n        }\n\n        if ($this->config['show_included_files']) {\n            $trace[] = [\n                'type' => 'groupCollapsed',\n                'msg'  => '[ file ]',\n                'css'  => '',\n            ];\n            $trace[] = [\n                'type' => 'log',\n                'msg'  => implode(\"\\n\", get_included_files()),\n                'css'  => '',\n            ];\n            $trace[] = [\n                'type' => 'groupEnd',\n                'msg'  => '',\n                'css'  => '',\n            ];\n        }\n\n        $trace[] = [\n            'type' => 'groupEnd',\n            'msg'  => '',\n            'css'  => '',\n        ];\n\n        $tabid = $this->getClientArg('tabid');\n        if (!$client_id = $this->getClientArg('client_id')) {\n            $client_id = '';\n        }\n\n        if (!empty($this->allowForceClientIds)) {\n            //强制推送到多个client_id\n            foreach ($this->allowForceClientIds as $force_client_id) {\n                $client_id = $force_client_id;\n                $this->sendToClient($tabid, $client_id, $trace, $force_client_id);\n            }\n        } else {\n            $this->sendToClient($tabid, $client_id, $trace, '');\n        }\n        return true;\n    }\n\n    /**\n     * 发送给指定客户端\n     * @author Zjmainstay\n     * @param $tabid\n     * @param $client_id\n     * @param $logs\n     * @param $force_client_id\n     */\n    protected function sendToClient($tabid, $client_id, $logs, $force_client_id)\n    {\n        $logs = [\n            'tabid'           => $tabid,\n            'client_id'       => $client_id,\n            'logs'            => $logs,\n            'force_client_id' => $force_client_id,\n        ];\n        $msg     = @json_encode($logs);\n        $address = '/' . $client_id; //将client_id作为地址， server端通过地址判断将日志发布给谁\n        $this->send($this->config['host'], $msg, $address);\n    }\n\n    protected function check()\n    {\n        $tabid = $this->getClientArg('tabid');\n        //是否记录日志的检查\n        if (!$tabid && !$this->config['force_client_ids']) {\n            return false;\n        }\n        //用户认证\n        $allow_client_ids = $this->config['allow_client_ids'];\n        if (!empty($allow_client_ids)) {\n            //通过数组交集得出授权强制推送的client_id\n            $this->allowForceClientIds = array_intersect($allow_client_ids, $this->config['force_client_ids']);\n            if (!$tabid && count($this->allowForceClientIds)) {\n                return true;\n            }\n\n            $client_id = $this->getClientArg('client_id');\n            if (!in_array($client_id, $allow_client_ids)) {\n                return false;\n            }\n        } else {\n            $this->allowForceClientIds = $this->config['force_client_ids'];\n        }\n        return true;\n    }\n\n    protected function getClientArg($name)\n    {\n        static $args = [];\n\n        $key = 'HTTP_USER_AGENT';\n\n        if (isset($_SERVER['HTTP_SOCKETLOG'])) {\n            $key = 'HTTP_SOCKETLOG';\n        }\n\n        if (!isset($_SERVER[$key])) {\n            return;\n        }\n        if (empty($args)) {\n            if (!preg_match('/SocketLog\\((.*?)\\)/', $_SERVER[$key], $match)) {\n                $args = ['tabid' => null];\n                return;\n            }\n            parse_str($match[1], $args);\n        }\n        if (isset($args[$name])) {\n            return $args[$name];\n        }\n        return;\n    }\n\n    /**\n     * @param string $host - $host of socket server\n     * @param string $message - 发送的消息\n     * @param string $address - 地址\n     * @return bool\n     */\n    protected function send($host, $message = '', $address = '/')\n    {\n        $url = 'http://' . $host . ':' . $this->port . $address;\n        $ch  = curl_init();\n        curl_setopt($ch, CURLOPT_URL, $url);\n        curl_setopt($ch, CURLOPT_POST, true);\n        curl_setopt($ch, CURLOPT_POSTFIELDS, $message);\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);\n        curl_setopt($ch, CURLOPT_TIMEOUT, 10);\n        $headers = [\n            \"Content-Type: application/json;charset=UTF-8\",\n        ];\n        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); //设置header\n        return curl_exec($ch);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/log/driver/Test.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\log\\driver;\n\n/**\n * 模拟测试输出\n */\nclass Test\n{\n    /**\n     * 日志写入接口\n     * @access public\n     * @param array $log 日志信息\n     * @return bool\n     */\n    public function save(array $log = [])\n    {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/Collection.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: zhangyajun <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model;\n\nuse think\\Collection as BaseCollection;\nuse think\\Model;\n\nclass Collection extends BaseCollection\n{\n    /**\n     * 返回数组中指定的一列\n     * @param string        $column_key\n     * @param string|null   $index_key\n     * @return array\n     */\n    public function column($column_key, $index_key = null)\n    {\n        if (function_exists('array_column')) {\n            return array_column($this->toArray(), $column_key, $index_key);\n        }\n        return parent::column($column_key, $index_key);\n    }\n\n    /**\n     * 延迟预载入关联查询\n     * @access public\n     * @param mixed $relation 关联\n     * @return $this\n     */\n    public function load($relation)\n    {\n        $item = current($this->items);\n        $item->eagerlyResultSet($this->items, $relation);\n        return $this;\n    }\n\n    /**\n     * 设置需要隐藏的输出属性\n     * @access public\n     * @param array $hidden   属性列表\n     * @param bool  $override 是否覆盖\n     * @return $this\n     */\n    public function hidden($hidden = [], $override = false)\n    {\n        $this->each(function ($model) use ($hidden, $override) {\n            /** @var Model $model */\n            $model->hidden($hidden, $override);\n        });\n        return $this;\n    }\n\n    /**\n     * 设置需要输出的属性\n     * @param array $visible\n     * @param bool  $override 是否覆盖\n     * @return $this\n     */\n    public function visible($visible = [], $override = false)\n    {\n        $this->each(function ($model) use ($visible, $override) {\n            /** @var Model $model */\n            $model->visible($visible, $override);\n        });\n        return $this;\n    }\n\n    /**\n     * 设置需要追加的输出属性\n     * @access public\n     * @param array $append   属性列表\n     * @param bool  $override 是否覆盖\n     * @return $this\n     */\n    public function append($append = [], $override = false)\n    {\n        $this->each(function ($model) use ($append, $override) {\n            /** @var Model $model */\n            $model->append($append, $override);\n        });\n        return $this;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/Merge.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model;\n\nuse think\\Db;\nuse think\\db\\Query;\nuse think\\Model;\n\nclass Merge extends Model\n{\n\n    protected $relationModel = []; // HAS ONE 关联的模型列表\n    protected $fk            = ''; //  外键名 默认为主表名_id\n    protected $mapFields     = []; //  需要处理的模型映射字段，避免混淆 array( id => 'user.id'  )\n\n    /**\n     * 构造函数\n     * @access public\n     * @param array|object $data 数据\n     */\n    public function __construct($data = [])\n    {\n        parent::__construct($data);\n\n        // 设置默认外键名 仅支持单一外键\n        if (empty($this->fk)) {\n            $this->fk = strtolower($this->name) . '_id';\n        }\n    }\n\n    /**\n     * 查找单条记录\n     * @access public\n     * @param mixed        $data  主键值或者查询条件（闭包）\n     * @param string|array $with  关联预查询\n     * @param bool         $cache 是否缓存\n     * @return \\think\\Model\n     */\n    public static function get($data = null, $with = [], $cache = false)\n    {\n        $query = self::parseQuery($data, $with, $cache);\n        $query = self::attachQuery($query);\n        return $query->find($data);\n    }\n\n    /**\n     * 附加查询表达式\n     * @access protected\n     * @param \\think\\db\\Query $query 查询对象\n     * @return \\think\\db\\Query\n     */\n    protected static function attachQuery($query)\n    {\n        $class  = new static();\n        $master = $class->name;\n        $fields = self::getModelField($query, $master, '', $class->mapFields, $class->field);\n        $query->alias($master)->field($fields);\n\n        foreach ($class->relationModel as $key => $model) {\n            $name  = is_int($key) ? $model : $key;\n            $table = is_int($key) ? $query->getTable($name) : $model;\n            $query->join($table . ' ' . $name, $name . '.' . $class->fk . '=' . $master . '.' . $class->getPk());\n            $fields = self::getModelField($query, $name, $table, $class->mapFields, $class->field);\n            $query->field($fields);\n        }\n        return $query;\n    }\n\n    /**\n     * 获取关联模型的字段 并解决混淆\n     * @access protected\n     * @param \\think\\db\\Query $query  查询对象\n     * @param string          $name   模型名称\n     * @param string          $table  关联表名称\n     * @param array           $map    字段映射\n     * @param array           $fields 查询字段\n     * @return array\n     */\n    protected static function getModelField($query, $name, $table = '', $map = [], $fields = [])\n    {\n        // 获取模型的字段信息\n        $fields = $fields ?: $query->getTableInfo($table, 'fields');\n        $array  = [];\n        foreach ($fields as $field) {\n            if ($key = array_search($name . '.' . $field, $map)) {\n                // 需要处理映射字段\n                $array[] = $name . '.' . $field . ' AS ' . $key;\n            } else {\n                $array[] = $field;\n            }\n        }\n        return $array;\n    }\n\n    /**\n     * 查找所有记录\n     * @access public\n     * @param mixed        $data 主键列表或者查询条件（闭包）\n     * @param array|string $with 关联预查询\n     * @param bool         $cache\n     * @return array|false|string\n     */\n    public static function all($data = null, $with = [], $cache = false)\n    {\n        $query = self::parseQuery($data, $with, $cache);\n        $query = self::attachQuery($query);\n        return $query->select($data);\n    }\n\n    /**\n     * 处理写入的模型数据\n     * @access public\n     * @param string $model  模型名称\n     * @param array  $data   数据\n     * @return array\n     */\n    protected function parseData($model, $data)\n    {\n        $item = [];\n        foreach ($data as $key => $val) {\n            if ($this->fk != $key && array_key_exists($key, $this->mapFields)) {\n                list($name, $key) = explode('.', $this->mapFields[$key]);\n                if ($model == $name) {\n                    $item[$key] = $val;\n                }\n            } else {\n                $item[$key] = $val;\n            }\n        }\n        return $item;\n    }\n\n    /**\n     * 保存模型数据 以及关联数据\n     * @access public\n     * @param mixed  $data     数据\n     * @param array  $where    更新条件\n     * @param string $sequence 自增序列名\n     * @return false|int\n     * @throws \\Exception\n     */\n    public function save($data = [], $where = [], $sequence = null)\n    {\n        if (!empty($data)) {\n            // 数据自动验证\n            if (!$this->validateData($data)) {\n                return false;\n            }\n            // 数据对象赋值\n            foreach ($data as $key => $value) {\n                $this->setAttr($key, $value, $data);\n            }\n            if (!empty($where)) {\n                $this->isUpdate = true;\n            }\n        }\n\n        // 数据自动完成\n        $this->autoCompleteData($this->auto);\n\n        // 自动写入更新时间\n        if ($this->autoWriteTimestamp && $this->updateTime && !isset($this->data[$this->updateTime])) {\n            $this->setAttr($this->updateTime, null);\n        }\n\n        // 事件回调\n        if (false === $this->trigger('before_write', $this)) {\n            return false;\n        }\n\n        $db = $this->db();\n        $db->startTrans();\n        $pk = $this->getPk();\n        try {\n            if ($this->isUpdate) {\n                // 自动写入\n                $this->autoCompleteData($this->update);\n\n                if (false === $this->trigger('before_update', $this)) {\n                    return false;\n                }\n\n                if (empty($where) && !empty($this->updateWhere)) {\n                    $where = $this->updateWhere;\n                }\n\n                // 获取有更新的数据\n                $data = $this->getChangedData();\n                // 保留主键数据\n                foreach ($this->data as $key => $val) {\n                    if ($this->isPk($key)) {\n                        $data[$key] = $val;\n                    }\n                }\n                // 处理模型数据\n                $data = $this->parseData($this->name, $data);\n                if (is_string($pk) && isset($data[$pk])) {\n                    if (!isset($where[$pk])) {\n                        unset($where);\n                        $where[$pk] = $data[$pk];\n                    }\n                    unset($data[$pk]);\n                }\n                // 写入主表数据\n                $result = $db->strict(false)->where($where)->update($data);\n\n                // 写入附表数据\n                foreach ($this->relationModel as $key => $model) {\n                    $name  = is_int($key) ? $model : $key;\n                    $table = is_int($key) ? $db->getTable($model) : $model;\n                    // 处理关联模型数据\n                    $data = $this->parseData($name, $data);\n                    if (Db::table($table)->strict(false)->where($this->fk, $this->data[$this->getPk()])->update($data)) {\n                        $result = 1;\n                    }\n                }\n\n                // 新增回调\n                $this->trigger('after_update', $this);\n            } else {\n                // 自动写入\n                $this->autoCompleteData($this->insert);\n\n                // 自动写入创建时间\n                if ($this->autoWriteTimestamp && $this->createTime && !isset($this->data[$this->createTime])) {\n                    $this->setAttr($this->createTime, null);\n                }\n\n                if (false === $this->trigger('before_insert', $this)) {\n                    return false;\n                }\n\n                // 处理模型数据\n                $data = $this->parseData($this->name, $this->data);\n                // 写入主表数据\n                $result = $db->name($this->name)->strict(false)->insert($data);\n                if ($result) {\n                    $insertId = $db->getLastInsID($sequence);\n                    // 写入外键数据\n                    if ($insertId) {\n                        if (is_string($pk)) {\n                            $this->data[$pk] = $insertId;\n                        }\n                        $this->data[$this->fk] = $insertId;\n                    }\n\n                    // 写入附表数据\n                    $source = $this->data;\n                    if ($insertId && is_string($pk) && isset($source[$pk]) && $this->fk != $pk) {\n                        unset($source[$pk]);\n                    }\n                    foreach ($this->relationModel as $key => $model) {\n                        $name  = is_int($key) ? $model : $key;\n                        $table = is_int($key) ? $db->getTable($model) : $model;\n                        // 处理关联模型数据\n                        $data = $this->parseData($name, $source);\n                        Db::table($table)->strict(false)->insert($data);\n                    }\n                }\n                // 标记为更新\n                $this->isUpdate = true;\n                // 新增回调\n                $this->trigger('after_insert', $this);\n            }\n            $db->commit();\n            // 写入回调\n            $this->trigger('after_write', $this);\n\n            $this->origin = $this->data;\n            return $result;\n        } catch (\\Exception $e) {\n            $db->rollback();\n            throw $e;\n        }\n    }\n\n    /**\n     * 删除当前的记录 并删除关联数据\n     * @access public\n     * @return int\n     * @throws \\Exception\n     */\n    public function delete()\n    {\n        if (false === $this->trigger('before_delete', $this)) {\n            return false;\n        }\n\n        $db = $this->db();\n        $db->startTrans();\n        try {\n            $result = $db->delete($this->data);\n            if ($result) {\n                // 获取主键数据\n                $pk = $this->data[$this->getPk()];\n\n                // 删除关联数据\n                foreach ($this->relationModel as $key => $model) {\n                    $table = is_int($key) ? $db->getTable($model) : $model;\n                    $query = new Query;\n                    $query->table($table)->where($this->fk, $pk)->delete();\n                }\n            }\n            $this->trigger('after_delete', $this);\n            $db->commit();\n            return $result;\n        } catch (\\Exception $e) {\n            $db->rollback();\n            throw $e;\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/Pivot.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model;\n\nuse think\\Model;\n\nclass Pivot extends Model\n{\n\n    /** @var Model */\n    public $parent;\n\n    protected $autoWriteTimestamp = false;\n\n    /**\n     * 架构函数\n     * @access public\n     * @param Model         $parent 上级模型\n     * @param array|object  $data 数据\n     * @param string        $table 中间数据表名\n     */\n    public function __construct(Model $parent, $data = [], $table = '')\n    {\n        $this->parent = $parent;\n\n        if (is_null($this->name)) {\n            $this->name = $table;\n        }\n\n        parent::__construct($data);\n\n        $this->class = $this->name;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/Relation.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model;\n\nuse think\\db\\Query;\nuse think\\Exception;\nuse think\\Model;\n\n/**\n * Class Relation\n * @package think\\model\n *\n * @mixin Query\n */\nabstract class Relation\n{\n    // 父模型对象\n    protected $parent;\n    /** @var  Model 当前关联的模型类 */\n    protected $model;\n    /** @var Query 关联模型查询对象 */\n    protected $query;\n    // 关联表外键\n    protected $foreignKey;\n    // 关联表主键\n    protected $localKey;\n    // 基础查询\n    protected $baseQuery;\n\n    /**\n     * 获取关联的所属模型\n     * @access public\n     * @return Model\n     */\n    public function getParent()\n    {\n        return $this->parent;\n    }\n\n    /**\n     * 获取当前的关联模型类\n     * @access public\n     * @return string\n     */\n    public function getModel()\n    {\n        return $this->model;\n    }\n\n    /**\n     * 获取关联的查询对象\n     * @access public\n     * @return Query\n     */\n    public function getQuery()\n    {\n        return $this->query;\n    }\n\n    /**\n     * 封装关联数据集\n     * @access public\n     * @param array $resultSet 数据集\n     * @return mixed\n     */\n    protected function resultSetBuild($resultSet)\n    {\n        return (new $this->model)->toCollection($resultSet);\n    }\n\n    protected function getQueryFields($model)\n    {\n        $fields = $this->query->getOptions('field');\n        return $this->getRelationQueryFields($fields, $model);\n    }\n\n    protected function getRelationQueryFields($fields, $model)\n    {\n        if ($fields) {\n\n            if (is_string($fields)) {\n                $fields = explode(',', $fields);\n            }\n\n            foreach ($fields as &$field) {\n                if (false === strpos($field, '.')) {\n                    $field = $model . '.' . $field;\n                }\n            }\n        } else {\n            $fields = $model . '.*';\n        }\n\n        return $fields;\n    }\n\n    /**\n     * 执行基础查询（仅执行一次）\n     * @access protected\n     * @return void\n     */\n    abstract protected function baseQuery();\n\n    public function __call($method, $args)\n    {\n        if ($this->query) {\n            // 执行基础查询\n            $this->baseQuery();\n\n            $result = call_user_func_array([$this->query, $method], $args);\n            if ($result instanceof Query) {\n                return $this;\n            } else {\n                $this->baseQuery = false;\n                return $result;\n            }\n        } else {\n            throw new Exception('method not exists:' . __CLASS__ . '->' . $method);\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/relation/BelongsTo.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model\\relation;\n\nuse think\\Loader;\nuse think\\Model;\n\nclass BelongsTo extends OneToOne\n{\n    /**\n     * 构造函数\n     * @access public\n     * @param Model  $parent 上级模型对象\n     * @param string $model 模型名\n     * @param string $foreignKey 关联外键\n     * @param string $localKey 关联主键\n     * @param string $joinType JOIN类型\n     * @param string $relation  关联名\n     */\n    public function __construct(Model $parent, $model, $foreignKey, $localKey, $joinType = 'INNER', $relation = null)\n    {\n        $this->parent     = $parent;\n        $this->model      = $model;\n        $this->foreignKey = $foreignKey;\n        $this->localKey   = $localKey;\n        $this->joinType   = $joinType;\n        $this->query      = (new $model)->db();\n        $this->relation   = $relation;\n    }\n\n    /**\n     * 延迟获取关联数据\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包查询条件\n     * @access public\n     * @return array|false|\\PDOStatement|string|Model\n     */\n    public function getRelation($subRelation = '', $closure = null)\n    {\n        $foreignKey = $this->foreignKey;\n        if ($closure) {\n            call_user_func_array($closure, [ & $this->query]);\n        }\n        $relationModel = $this->query\n            ->where($this->localKey, $this->parent->$foreignKey)\n            ->relation($subRelation)\n            ->find();\n\n        if ($relationModel) {\n            $relationModel->setParent(clone $this->parent);\n        }\n\n        return $relationModel;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param string  $operator 比较操作符\n     * @param integer $count    个数\n     * @param string  $id       关联表的统计字段\n     * @param string  $joinType JOIN类型\n     * @return Query\n     */\n    public function has($operator = '>=', $count = 1, $id = '*')\n    {\n        return $this->parent;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param mixed $where 查询条件（数组或者闭包）\n     * @return Query\n     */\n    public function hasWhere($where = [])\n    {\n        $table    = $this->query->getTable();\n        $model    = basename(str_replace('\\\\', '/', get_class($this->parent)));\n        $relation = basename(str_replace('\\\\', '/', $this->model));\n        if (is_array($where)) {\n            foreach ($where as $key => $val) {\n                if (false === strpos($key, '.')) {\n                    $where[$relation . '.' . $key] = $val;\n                    unset($where[$key]);\n                }\n            }\n        }\n        return $this->parent->db()->alias($model)\n            ->field($model . '.*')\n            ->join($table . ' ' . $relation, $model . '.' . $this->foreignKey . '=' . $relation . '.' . $this->localKey, $this->joinType)\n            ->where($where);\n    }\n\n    /**\n     * 预载入关联查询（数据集）\n     * @access public\n     * @param array     $resultSet 数据集\n     * @param string    $relation 当前关联名\n     * @param string    $subRelation 子关联名\n     * @param \\Closure  $closure 闭包\n     * @return void\n     */\n    protected function eagerlySet(&$resultSet, $relation, $subRelation, $closure)\n    {\n        $localKey   = $this->localKey;\n        $foreignKey = $this->foreignKey;\n\n        $range = [];\n        foreach ($resultSet as $result) {\n            // 获取关联外键列表\n            if (isset($result->$foreignKey)) {\n                $range[] = $result->$foreignKey;\n            }\n        }\n\n        if (!empty($range)) {\n            $data = $this->eagerlyWhere($this, [\n                $localKey => [\n                    'in',\n                    $range,\n                ],\n            ], $localKey, $relation, $subRelation, $closure);\n            // 关联属性名\n            $attr = Loader::parseName($relation);\n            // 关联数据封装\n            foreach ($resultSet as $result) {\n                // 关联模型\n                if (!isset($data[$result->$foreignKey])) {\n                    $relationModel = null;\n                } else {\n                    $relationModel = $data[$result->$foreignKey];\n                    $relationModel->setParent(clone $result);\n                    $relationModel->isUpdate(true);\n                }\n\n                if ($relationModel && !empty($this->bindAttr)) {\n                    // 绑定关联属性\n                    $this->bindAttr($relationModel, $result, $this->bindAttr);\n                }\n                // 设置关联属性\n                $result->setRelation($attr, $relationModel);\n            }\n        }\n    }\n\n    /**\n     * 预载入关联查询（数据）\n     * @access public\n     * @param Model     $result 数据对象\n     * @param string    $relation 当前关联名\n     * @param string    $subRelation 子关联名\n     * @param \\Closure  $closure 闭包\n     * @return void\n     */\n    protected function eagerlyOne(&$result, $relation, $subRelation, $closure)\n    {\n        $localKey   = $this->localKey;\n        $foreignKey = $this->foreignKey;\n        $data       = $this->eagerlyWhere($this, [$localKey => $result->$foreignKey], $localKey, $relation, $subRelation, $closure);\n        // 关联模型\n        if (!isset($data[$result->$foreignKey])) {\n            $relationModel = null;\n        } else {\n            $relationModel = $data[$result->$foreignKey];\n            $relationModel->setParent(clone $result);\n            $relationModel->isUpdate(true);\n        }\n        if ($relationModel && !empty($this->bindAttr)) {\n            // 绑定关联属性\n            $this->bindAttr($relationModel, $result, $this->bindAttr);\n        }\n        // 设置关联属性\n        $result->setRelation(Loader::parseName($relation), $relationModel);\n    }\n\n    /**\n     * 添加关联数据\n     * @access public\n     * @param Model $model       关联模型对象\n     * @return Model\n     */\n    public function associate($model)\n    {\n        $foreignKey = $this->foreignKey;\n        $pk         = $model->getPk();\n\n        $this->parent->setAttr($foreignKey, $model->$pk);\n        $this->parent->save();\n\n        return $this->parent->setRelation($this->relation, $model);\n    }\n\n    /**\n     * 注销关联数据\n     * @access public\n     * @return Model\n     */\n    public function dissociate()\n    {\n        $foreignKey = $this->foreignKey;\n\n        $this->parent->setAttr($foreignKey, null);\n        $this->parent->save();\n\n        return $this->parent->setRelation($this->relation, null);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/relation/BelongsToMany.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model\\relation;\n\nuse think\\Collection;\nuse think\\db\\Query;\nuse think\\Exception;\nuse think\\Loader;\nuse think\\Model;\nuse think\\model\\Pivot;\nuse think\\model\\Relation;\nuse think\\Paginator;\n\nclass BelongsToMany extends Relation\n{\n    // 中间表表名\n    protected $middle;\n    // 中间表模型名称\n    protected $pivotName;\n    // 中间表模型对象\n    protected $pivot;\n\n    /**\n     * 构造函数\n     * @access public\n     * @param Model  $parent     上级模型对象\n     * @param string $model      模型名\n     * @param string $table      中间表名\n     * @param string $foreignKey 关联模型外键\n     * @param string $localKey   当前模型关联键\n     */\n    public function __construct(Model $parent, $model, $table, $foreignKey, $localKey)\n    {\n        $this->parent     = $parent;\n        $this->model      = $model;\n        $this->foreignKey = $foreignKey;\n        $this->localKey   = $localKey;\n        if (false !== strpos($table, '\\\\')) {\n            $this->pivotName = $table;\n            $this->middle    = basename(str_replace('\\\\', '/', $table));\n        } else {\n            $this->middle = $table;\n        }\n        $this->query = (new $model)->db();\n        $this->pivot = $this->newPivot();\n    }\n\n    /**\n     * 设置中间表模型\n     * @param $pivot\n     * @return $this\n     */\n    public function pivot($pivot)\n    {\n        $this->pivotName = $pivot;\n        return $this;\n    }\n\n    /**\n     * 实例化中间表模型\n     * @param $data\n     * @return mixed\n     */\n    protected function newPivot($data = [])\n    {\n        $pivot = $this->pivotName ?: '\\\\think\\\\model\\\\Pivot';\n        return new $pivot($this->parent, $data, $this->middle);\n    }\n\n    /**\n     * 合成中间表模型\n     * @param array|Collection|Paginator $models\n     */\n    protected function hydratePivot($models)\n    {\n        foreach ($models as $model) {\n            $pivot = [];\n            foreach ($model->getData() as $key => $val) {\n                if (strpos($key, '__')) {\n                    list($name, $attr) = explode('__', $key, 2);\n                    if ('pivot' == $name) {\n                        $pivot[$attr] = $val;\n                        unset($model->$key);\n                    }\n                }\n            }\n            $model->setRelation('pivot', $this->newPivot($pivot));\n        }\n    }\n\n    /**\n     * 创建关联查询Query对象\n     * @return Query\n     */\n    protected function buildQuery()\n    {\n        $foreignKey = $this->foreignKey;\n        $localKey   = $this->localKey;\n        $pk         = $this->parent->getPk();\n        // 关联查询\n        $condition['pivot.' . $localKey] = $this->parent->$pk;\n        return $this->belongsToManyQuery($foreignKey, $localKey, $condition);\n    }\n\n    /**\n     * 延迟获取关联数据\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包查询条件\n     * @return false|\\PDOStatement|string|\\think\\Collection\n     */\n    public function getRelation($subRelation = '', $closure = null)\n    {\n        if ($closure) {\n            call_user_func_array($closure, [ & $this->query]);\n        }\n        $result = $this->buildQuery()->relation($subRelation)->select();\n        $this->hydratePivot($result);\n        return $result;\n    }\n\n    /**\n     * 重载select方法\n     * @param null $data\n     * @return false|\\PDOStatement|string|Collection\n     */\n    public function select($data = null)\n    {\n        $result = $this->buildQuery()->select($data);\n        $this->hydratePivot($result);\n        return $result;\n    }\n\n    /**\n     * 重载paginate方法\n     * @param null  $listRows\n     * @param bool  $simple\n     * @param array $config\n     * @return Paginator\n     */\n    public function paginate($listRows = null, $simple = false, $config = [])\n    {\n        $result = $this->buildQuery()->paginate($listRows, $simple, $config);\n        $this->hydratePivot($result);\n        return $result;\n    }\n\n    /**\n     * 重载find方法\n     * @param null $data\n     * @return array|false|\\PDOStatement|string|Model\n     */\n    public function find($data = null)\n    {\n        $result = $this->buildQuery()->find($data);\n        if ($result) {\n            $this->hydratePivot([$result]);\n        }\n        return $result;\n    }\n\n    /**\n     * 查找多条记录 如果不存在则抛出异常\n     * @access public\n     * @param array|string|Query|\\Closure $data\n     * @return array|\\PDOStatement|string|Model\n     */\n    public function selectOrFail($data = null)\n    {\n        return $this->failException(true)->select($data);\n    }\n\n    /**\n     * 查找单条记录 如果不存在则抛出异常\n     * @access public\n     * @param array|string|Query|\\Closure $data\n     * @return array|\\PDOStatement|string|Model\n     */\n    public function findOrFail($data = null)\n    {\n        return $this->failException(true)->find($data);\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param string  $operator 比较操作符\n     * @param integer $count    个数\n     * @param string  $id       关联表的统计字段\n     * @param string  $joinType JOIN类型\n     * @return Query\n     */\n    public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')\n    {\n        return $this->parent;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param mixed $where 查询条件（数组或者闭包）\n     * @return Query\n     * @throws Exception\n     */\n    public function hasWhere($where = [])\n    {\n        throw new Exception('relation not support: hasWhere');\n    }\n\n    /**\n     * 设置中间表的查询条件\n     * @param      $field\n     * @param null $op\n     * @param null $condition\n     * @return $this\n     */\n    public function wherePivot($field, $op = null, $condition = null)\n    {\n        $field = 'pivot.' . $field;\n        $this->query->where($field, $op, $condition);\n        return $this;\n    }\n\n    /**\n     * 预载入关联查询（数据集）\n     * @access public\n     * @param array    $resultSet   数据集\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)\n    {\n        $localKey   = $this->localKey;\n        $foreignKey = $this->foreignKey;\n\n        $pk    = $resultSet[0]->getPk();\n        $range = [];\n        foreach ($resultSet as $result) {\n            // 获取关联外键列表\n            if (isset($result->$pk)) {\n                $range[] = $result->$pk;\n            }\n        }\n\n        if (!empty($range)) {\n            // 查询关联数据\n            $data = $this->eagerlyManyToMany([\n                'pivot.' . $localKey => [\n                    'in',\n                    $range,\n                ],\n            ], $relation, $subRelation);\n            // 关联属性名\n            $attr = Loader::parseName($relation);\n            // 关联数据封装\n            foreach ($resultSet as $result) {\n                if (!isset($data[$result->$pk])) {\n                    $data[$result->$pk] = [];\n                }\n\n                $result->setRelation($attr, $this->resultSetBuild($data[$result->$pk]));\n            }\n        }\n    }\n\n    /**\n     * 预载入关联查询（单个数据）\n     * @access public\n     * @param Model    $result      数据对象\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResult(&$result, $relation, $subRelation, $closure)\n    {\n        $pk = $result->getPk();\n        if (isset($result->$pk)) {\n            $pk = $result->$pk;\n            // 查询管理数据\n            $data = $this->eagerlyManyToMany(['pivot.' . $this->localKey => $pk], $relation, $subRelation);\n\n            // 关联数据封装\n            if (!isset($data[$pk])) {\n                $data[$pk] = [];\n            }\n            $result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$pk]));\n        }\n    }\n\n    /**\n     * 关联统计\n     * @access public\n     * @param Model    $result  数据对象\n     * @param \\Closure $closure 闭包\n     * @return integer\n     */\n    public function relationCount($result, $closure)\n    {\n        $pk    = $result->getPk();\n        $count = 0;\n        if (isset($result->$pk)) {\n            $pk    = $result->$pk;\n            $count = $this->belongsToManyQuery($this->foreignKey, $this->localKey, ['pivot.' . $this->localKey => $pk])->count();\n        }\n        return $count;\n    }\n\n    /**\n     * 获取关联统计子查询\n     * @access public\n     * @param \\Closure $closure 闭包\n     * @return string\n     */\n    public function getRelationCountQuery($closure)\n    {\n        return $this->belongsToManyQuery($this->foreignKey, $this->localKey, [\n            'pivot.' . $this->localKey => [\n                'exp',\n                '=' . $this->parent->getTable() . '.' . $this->parent->getPk(),\n            ],\n        ])->fetchSql()->count();\n    }\n\n    /**\n     * 多对多 关联模型预查询\n     * @access public\n     * @param array  $where       关联预查询条件\n     * @param string $relation    关联名\n     * @param string $subRelation 子关联\n     * @return array\n     */\n    protected function eagerlyManyToMany($where, $relation, $subRelation = '')\n    {\n        // 预载入关联查询 支持嵌套预载入\n        $list = $this->belongsToManyQuery($this->foreignKey, $this->localKey, $where)->with($subRelation)->select();\n\n        // 组装模型数据\n        $data = [];\n        foreach ($list as $set) {\n            $pivot = [];\n            foreach ($set->getData() as $key => $val) {\n                if (strpos($key, '__')) {\n                    list($name, $attr) = explode('__', $key, 2);\n                    if ('pivot' == $name) {\n                        $pivot[$attr] = $val;\n                        unset($set->$key);\n                    }\n                }\n            }\n            $set->setRelation('pivot', $this->newPivot($pivot));\n            $data[$pivot[$this->localKey]][] = $set;\n        }\n        return $data;\n    }\n\n    /**\n     * BELONGS TO MANY 关联查询\n     * @access public\n     * @param string $foreignKey 关联模型关联键\n     * @param string $localKey   当前模型关联键\n     * @param array  $condition  关联查询条件\n     * @return Query\n     */\n    protected function belongsToManyQuery($foreignKey, $localKey, $condition = [])\n    {\n        // 关联查询封装\n        $tableName = $this->query->getTable();\n        $table     = $this->pivot->getTable();\n        $fields    = $this->getQueryFields($tableName);\n\n        $query = $this->query->field($fields)\n            ->field(true, false, $table, 'pivot', 'pivot__');\n\n        if (empty($this->baseQuery)) {\n            $relationFk = $this->query->getPk();\n            $query->join($table . ' pivot', 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk)\n                ->where($condition);\n        }\n        return $query;\n    }\n\n    /**\n     * 保存（新增）当前关联数据对象\n     * @access public\n     * @param mixed $data  数据 可以使用数组 关联模型对象 和 关联对象的主键\n     * @param array $pivot 中间表额外数据\n     * @return integer\n     */\n    public function save($data, array $pivot = [])\n    {\n        // 保存关联表/中间表数据\n        return $this->attach($data, $pivot);\n    }\n\n    /**\n     * 批量保存当前关联数据对象\n     * @access public\n     * @param array $dataSet   数据集\n     * @param array $pivot     中间表额外数据\n     * @param bool  $samePivot 额外数据是否相同\n     * @return integer\n     */\n    public function saveAll(array $dataSet, array $pivot = [], $samePivot = false)\n    {\n        $result = false;\n        foreach ($dataSet as $key => $data) {\n            if (!$samePivot) {\n                $pivotData = isset($pivot[$key]) ? $pivot[$key] : [];\n            } else {\n                $pivotData = $pivot;\n            }\n            $result = $this->attach($data, $pivotData);\n        }\n        return $result;\n    }\n\n    /**\n     * 附加关联的一个中间表数据\n     * @access public\n     * @param mixed $data  数据 可以使用数组、关联模型对象 或者 关联对象的主键\n     * @param array $pivot 中间表额外数据\n     * @return array|Pivot\n     * @throws Exception\n     */\n    public function attach($data, $pivot = [])\n    {\n        if (is_array($data)) {\n            if (key($data) === 0) {\n                $id = $data;\n            } else {\n                // 保存关联表数据\n                $model = new $this->model;\n                $model->save($data);\n                $id = $model->getLastInsID();\n            }\n        } elseif (is_numeric($data) || is_string($data)) {\n            // 根据关联表主键直接写入中间表\n            $id = $data;\n        } elseif ($data instanceof Model) {\n            // 根据关联表主键直接写入中间表\n            $relationFk = $data->getPk();\n            $id         = $data->$relationFk;\n        }\n\n        if ($id) {\n            // 保存中间表数据\n            $pk                     = $this->parent->getPk();\n            $pivot[$this->localKey] = $this->parent->$pk;\n            $ids                    = (array) $id;\n            foreach ($ids as $id) {\n                $pivot[$this->foreignKey] = $id;\n                $this->pivot->insert($pivot, true);\n                $result[] = $this->newPivot($pivot);\n            }\n            if (count($result) == 1) {\n                // 返回中间表模型对象\n                $result = $result[0];\n            }\n            return $result;\n        } else {\n            throw new Exception('miss relation data');\n        }\n    }\n\n    /**\n     * 解除关联的一个中间表数据\n     * @access public\n     * @param integer|array $data        数据 可以使用关联对象的主键\n     * @param bool          $relationDel 是否同时删除关联表数据\n     * @return integer\n     */\n    public function detach($data = null, $relationDel = false)\n    {\n        if (is_array($data)) {\n            $id = $data;\n        } elseif (is_numeric($data) || is_string($data)) {\n            // 根据关联表主键直接写入中间表\n            $id = $data;\n        } elseif ($data instanceof Model) {\n            // 根据关联表主键直接写入中间表\n            $relationFk = $data->getPk();\n            $id         = $data->$relationFk;\n        }\n        // 删除中间表数据\n        $pk                     = $this->parent->getPk();\n        $pivot[$this->localKey] = $this->parent->$pk;\n        if (isset($id)) {\n            $pivot[$this->foreignKey] = is_array($id) ? ['in', $id] : $id;\n        }\n        $this->pivot->where($pivot)->delete();\n        // 删除关联表数据\n        if (isset($id) && $relationDel) {\n            $model = $this->model;\n            $model::destroy($id);\n        }\n    }\n\n    /**\n     * 数据同步\n     * @param array $ids\n     * @param bool  $detaching\n     * @return array\n     */\n    public function sync($ids, $detaching = true)\n    {\n        $changes = [\n            'attached' => [],\n            'detached' => [],\n            'updated'  => [],\n        ];\n        $pk      = $this->parent->getPk();\n        $current = $this->pivot->where($this->localKey, $this->parent->$pk)\n            ->column($this->foreignKey);\n        $records = [];\n\n        foreach ($ids as $key => $value) {\n            if (!is_array($value)) {\n                $records[$value] = [];\n            } else {\n                $records[$key] = $value;\n            }\n        }\n\n        $detach = array_diff($current, array_keys($records));\n\n        if ($detaching && count($detach) > 0) {\n            $this->detach($detach);\n\n            $changes['detached'] = $detach;\n        }\n\n        foreach ($records as $id => $attributes) {\n            if (!in_array($id, $current)) {\n                $this->attach($id, $attributes);\n                $changes['attached'][] = $id;\n            } elseif (count($attributes) > 0 &&\n                $this->attach($id, $attributes)\n            ) {\n                $changes['updated'][] = $id;\n            }\n        }\n\n        return $changes;\n\n    }\n\n    /**\n     * 执行基础查询（进执行一次）\n     * @access protected\n     * @return void\n     */\n    protected function baseQuery()\n    {\n        if (empty($this->baseQuery) && $this->parent->getData()) {\n            $pk    = $this->parent->getPk();\n            $table = $this->pivot->getTable();\n            $this->query->join($table . ' pivot', 'pivot.' . $this->foreignKey . '=' . $this->query->getTable() . '.' . $this->query->getPk())->where('pivot.' . $this->localKey, $this->parent->$pk);\n            $this->baseQuery = true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/relation/HasMany.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model\\relation;\n\nuse think\\db\\Query;\nuse think\\Loader;\nuse think\\Model;\nuse think\\model\\Relation;\n\nclass HasMany extends Relation\n{\n    /**\n     * 构造函数\n     * @access public\n     * @param Model  $parent     上级模型对象\n     * @param string $model      模型名\n     * @param string $foreignKey 关联外键\n     * @param string $localKey   关联主键\n     */\n    public function __construct(Model $parent, $model, $foreignKey, $localKey)\n    {\n        $this->parent     = $parent;\n        $this->model      = $model;\n        $this->foreignKey = $foreignKey;\n        $this->localKey   = $localKey;\n        $this->query      = (new $model)->db();\n    }\n\n    /**\n     * 延迟获取关联数据\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包查询条件\n     * @return false|\\PDOStatement|string|\\think\\Collection\n     */\n    public function getRelation($subRelation = '', $closure = null)\n    {\n        if ($closure) {\n            call_user_func_array($closure, [ & $this->query]);\n        }\n        $list   = $this->relation($subRelation)->select();\n        $parent = clone $this->parent;\n\n        foreach ($list as &$model) {\n            $model->setParent($parent);\n        }\n\n        return $list;\n    }\n\n    /**\n     * 预载入关联查询\n     * @access   public\n     * @param array    $resultSet   数据集\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)\n    {\n        $localKey = $this->localKey;\n        $range    = [];\n        foreach ($resultSet as $result) {\n            // 获取关联外键列表\n            if (isset($result->$localKey)) {\n                $range[] = $result->$localKey;\n            }\n        }\n\n        if (!empty($range)) {\n            $data = $this->eagerlyOneToMany($this, [\n                $this->foreignKey => [\n                    'in',\n                    $range,\n                ],\n            ], $relation, $subRelation, $closure);\n            // 关联属性名\n            $attr = Loader::parseName($relation);\n            // 关联数据封装\n            foreach ($resultSet as $result) {\n                if (!isset($data[$result->$localKey])) {\n                    $data[$result->$localKey] = [];\n                }\n\n                foreach ($data[$result->$localKey] as &$relationModel) {\n                    $relationModel->setParent(clone $result);\n                }\n\n                $result->setRelation($attr, $this->resultSetBuild($data[$result->$localKey]));\n            }\n        }\n    }\n\n    /**\n     * 预载入关联查询\n     * @access   public\n     * @param Model    $result      数据对象\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResult(&$result, $relation, $subRelation, $closure)\n    {\n        $localKey = $this->localKey;\n\n        if (isset($result->$localKey)) {\n            $data = $this->eagerlyOneToMany($this, [$this->foreignKey => $result->$localKey], $relation, $subRelation, $closure);\n            // 关联数据封装\n            if (!isset($data[$result->$localKey])) {\n                $data[$result->$localKey] = [];\n            }\n\n            foreach ($data[$result->$localKey] as &$relationModel) {\n                $relationModel->setParent(clone $result);\n            }\n\n            $result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$result->$localKey]));\n        }\n    }\n\n    /**\n     * 关联统计\n     * @access public\n     * @param Model    $result  数据对象\n     * @param \\Closure $closure 闭包\n     * @return integer\n     */\n    public function relationCount($result, $closure)\n    {\n        $localKey = $this->localKey;\n        $count    = 0;\n        if (isset($result->$localKey)) {\n            if ($closure) {\n                call_user_func_array($closure, [ & $this->query]);\n            }\n            $count = $this->query->where([$this->foreignKey => $result->$localKey])->count();\n        }\n        return $count;\n    }\n\n    /**\n     * 创建关联统计子查询\n     * @access public\n     * @param \\Closure $closure 闭包\n     * @return string\n     */\n    public function getRelationCountQuery($closure)\n    {\n        if ($closure) {\n            call_user_func_array($closure, [ & $this->query]);\n        }\n\n        return $this->query->where([\n            $this->foreignKey => [\n                'exp',\n                '=' . $this->parent->getTable() . '.' . $this->parent->getPk(),\n            ],\n        ])->fetchSql()->count();\n    }\n\n    /**\n     * 一对多 关联模型预查询\n     * @access public\n     * @param object $model       关联模型对象\n     * @param array  $where       关联预查询条件\n     * @param string $relation    关联名\n     * @param string $subRelation 子关联\n     * @param bool   $closure\n     * @return array\n     */\n    protected function eagerlyOneToMany($model, $where, $relation, $subRelation = '', $closure = false)\n    {\n        $foreignKey = $this->foreignKey;\n        // 预载入关联查询 支持嵌套预载入\n        if ($closure) {\n            call_user_func_array($closure, [ & $model]);\n        }\n        $list = $model->where($where)->with($subRelation)->select();\n\n        // 组装模型数据\n        $data = [];\n        foreach ($list as $set) {\n            $data[$set->$foreignKey][] = $set;\n        }\n        return $data;\n    }\n\n    /**\n     * 保存（新增）当前关联数据对象\n     * @access public\n     * @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键\n     * @return Model|false\n     */\n    public function save($data)\n    {\n        if ($data instanceof Model) {\n            $data = $data->getData();\n        }\n        // 保存关联表数据\n        $model                   = new $this->model;\n        $data[$this->foreignKey] = $this->parent->{$this->localKey};\n        return $model->save($data) ? $model : false;\n    }\n\n    /**\n     * 批量保存当前关联数据对象\n     * @access public\n     * @param array $dataSet 数据集\n     * @return integer\n     */\n    public function saveAll(array $dataSet)\n    {\n        $result = false;\n        foreach ($dataSet as $key => $data) {\n            $result = $this->save($data);\n        }\n        return $result;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param string  $operator 比较操作符\n     * @param integer $count    个数\n     * @param string  $id       关联表的统计字段\n     * @param string  $joinType JOIN类型\n     * @return Query\n     */\n    public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')\n    {\n        $table = $this->query->getTable();\n        return $this->parent->db()->alias('a')\n            ->join($table . ' b', 'a.' . $this->localKey . '=b.' . $this->foreignKey, $joinType)\n            ->group('b.' . $this->foreignKey)\n            ->having('count(' . $id . ')' . $operator . $count);\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param mixed $where 查询条件（数组或者闭包）\n     * @return Query\n     */\n    public function hasWhere($where = [])\n    {\n        $table    = $this->query->getTable();\n        $model    = basename(str_replace('\\\\', '/', get_class($this->parent)));\n        $relation = basename(str_replace('\\\\', '/', $this->model));\n        if (is_array($where)) {\n            foreach ($where as $key => $val) {\n                if (false === strpos($key, '.')) {\n                    $where[$relation . '.' . $key] = $val;\n                    unset($where[$key]);\n                }\n            }\n        }\n        return $this->parent->db()->alias($model)\n            ->field($model . '.*')\n            ->join($table . ' ' . $relation, $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey)\n            ->where($where);\n    }\n\n    /**\n     * 执行基础查询（进执行一次）\n     * @access protected\n     * @return void\n     */\n    protected function baseQuery()\n    {\n        if (empty($this->baseQuery)) {\n            if (isset($this->parent->{$this->localKey})) {\n                // 关联查询带入关联条件\n                $this->query->where($this->foreignKey, $this->parent->{$this->localKey});\n            }\n            $this->baseQuery = true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/relation/HasManyThrough.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model\\relation;\n\nuse think\\db\\Query;\nuse think\\Exception;\nuse think\\Loader;\nuse think\\Model;\nuse think\\model\\Relation;\n\nclass HasManyThrough extends Relation\n{\n    // 中间关联表外键\n    protected $throughKey;\n    // 中间表模型\n    protected $through;\n\n    /**\n     * 构造函数\n     * @access   public\n     * @param Model  $parent     上级模型对象\n     * @param string $model      模型名\n     * @param string $through    中间模型名\n     * @param string $foreignKey 关联外键\n     * @param string $throughKey 关联外键\n     * @param string $localKey   关联主键\n     */\n    public function __construct(Model $parent, $model, $through, $foreignKey, $throughKey, $localKey)\n    {\n        $this->parent     = $parent;\n        $this->model      = $model;\n        $this->through    = $through;\n        $this->foreignKey = $foreignKey;\n        $this->throughKey = $throughKey;\n        $this->localKey   = $localKey;\n        $this->query      = (new $model)->db();\n    }\n\n    /**\n     * 延迟获取关联数据\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包查询条件\n     * @return false|\\PDOStatement|string|\\think\\Collection\n     */\n    public function getRelation($subRelation = '', $closure = null)\n    {\n        if ($closure) {\n            call_user_func_array($closure, [ & $this->query]);\n        }\n\n        return $this->relation($subRelation)->select();\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param string  $operator 比较操作符\n     * @param integer $count    个数\n     * @param string  $id       关联表的统计字段\n     * @param string  $joinType JOIN类型\n     * @return Query\n     */\n    public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')\n    {\n        return $this->parent;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param mixed $where 查询条件（数组或者闭包）\n     * @return Query\n     */\n    public function hasWhere($where = [])\n    {\n        throw new Exception('relation not support: hasWhere');\n    }\n\n    /**\n     * 预载入关联查询\n     * @access public\n     * @param array    $resultSet   数据集\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @param string   $class       数据集对象名 为空表示数组\n     * @return void\n     */\n    public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $class)\n    {}\n\n    /**\n     * 预载入关联查询 返回模型对象\n     * @access public\n     * @param Model    $result      数据对象\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @param string   $class       数据集对象名 为空表示数组\n     * @return void\n     */\n    public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class)\n    {}\n\n    /**\n     * 关联统计\n     * @access public\n     * @param Model    $result  数据对象\n     * @param \\Closure $closure 闭包\n     * @return integer\n     */\n    public function relationCount($result, $closure)\n    {}\n\n    /**\n     * 执行基础查询（进执行一次）\n     * @access protected\n     * @return void\n     */\n    protected function baseQuery()\n    {\n        if (empty($this->baseQuery) && $this->parent->getData()) {\n            $through      = $this->through;\n            $alias        = Loader::parseName(basename(str_replace('\\\\', '/', $this->model)));\n            $throughTable = $through::getTable();\n            $pk           = (new $through)->getPk();\n            $throughKey   = $this->throughKey;\n            $modelTable   = $this->parent->getTable();\n            $this->query->field($alias . '.*')->alias($alias)\n                ->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey)\n                ->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey)\n                ->where($throughTable . '.' . $this->foreignKey, $this->parent->{$this->localKey});\n            $this->baseQuery = true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/relation/HasOne.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model\\relation;\n\nuse think\\db\\Query;\nuse think\\Loader;\nuse think\\Model;\n\nclass HasOne extends OneToOne\n{\n    /**\n     * 构造函数\n     * @access public\n     * @param Model  $parent     上级模型对象\n     * @param string $model      模型名\n     * @param string $foreignKey 关联外键\n     * @param string $localKey   关联主键\n     * @param string $joinType   JOIN类型\n     */\n    public function __construct(Model $parent, $model, $foreignKey, $localKey, $joinType = 'INNER')\n    {\n        $this->parent     = $parent;\n        $this->model      = $model;\n        $this->foreignKey = $foreignKey;\n        $this->localKey   = $localKey;\n        $this->joinType   = $joinType;\n        $this->query      = (new $model)->db();\n    }\n\n    /**\n     * 延迟获取关联数据\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包查询条件\n     * @return array|false|\\PDOStatement|string|Model\n     */\n    public function getRelation($subRelation = '', $closure = null)\n    {\n        // 执行关联定义方法\n        $localKey = $this->localKey;\n        if ($closure) {\n            call_user_func_array($closure, [ & $this->query]);\n        }\n        // 判断关联类型执行查询\n        $relationModel = $this->query->where($this->foreignKey, $this->parent->$localKey)->relation($subRelation)->find();\n\n        if ($relationModel) {\n            $relationModel->setParent(clone $this->parent);\n        }\n\n        return $relationModel;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @return Query\n     */\n    public function has()\n    {\n        $table      = $this->query->getTable();\n        $localKey   = $this->localKey;\n        $foreignKey = $this->foreignKey;\n        return $this->parent->db()->alias('a')\n            ->whereExists(function ($query) use ($table, $localKey, $foreignKey) {\n                $query->table([$table => 'b'])->field('b.' . $foreignKey)->whereExp('a.' . $localKey, '=b.' . $foreignKey);\n            });\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param mixed $where 查询条件（数组或者闭包）\n     * @return Query\n     */\n    public function hasWhere($where = [])\n    {\n        $table    = $this->query->getTable();\n        $model    = basename(str_replace('\\\\', '/', get_class($this->parent)));\n        $relation = basename(str_replace('\\\\', '/', $this->model));\n        if (is_array($where)) {\n            foreach ($where as $key => $val) {\n                if (false === strpos($key, '.')) {\n                    $where[$relation . '.' . $key] = $val;\n                    unset($where[$key]);\n                }\n            }\n        }\n        return $this->parent->db()->alias($model)\n            ->field($model . '.*')\n            ->join($table . ' ' . $relation, $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $this->joinType)\n            ->where($where);\n    }\n\n    /**\n     * 预载入关联查询（数据集）\n     * @access public\n     * @param array    $resultSet   数据集\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    protected function eagerlySet(&$resultSet, $relation, $subRelation, $closure)\n    {\n        $localKey   = $this->localKey;\n        $foreignKey = $this->foreignKey;\n\n        $range = [];\n        foreach ($resultSet as $result) {\n            // 获取关联外键列表\n            if (isset($result->$localKey)) {\n                $range[] = $result->$localKey;\n            }\n        }\n\n        if (!empty($range)) {\n            $data = $this->eagerlyWhere($this, [\n                $foreignKey => [\n                    'in',\n                    $range,\n                ],\n            ], $foreignKey, $relation, $subRelation, $closure);\n            // 关联属性名\n            $attr = Loader::parseName($relation);\n            // 关联数据封装\n            foreach ($resultSet as $result) {\n                // 关联模型\n                if (!isset($data[$result->$localKey])) {\n                    $relationModel = null;\n                } else {\n                    $relationModel = $data[$result->$localKey];\n                    $relationModel->setParent(clone $result);\n                    $relationModel->isUpdate(true);\n                    if (!empty($this->bindAttr)) {\n                        // 绑定关联属性\n                        $this->bindAttr($relationModel, $result, $this->bindAttr);\n                    }\n                }\n                // 设置关联属性\n                $result->setRelation($attr, $relationModel);\n            }\n        }\n    }\n\n    /**\n     * 预载入关联查询（数据）\n     * @access public\n     * @param Model    $result      数据对象\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    protected function eagerlyOne(&$result, $relation, $subRelation, $closure)\n    {\n        $localKey   = $this->localKey;\n        $foreignKey = $this->foreignKey;\n        $data       = $this->eagerlyWhere($this, [$foreignKey => $result->$localKey], $foreignKey, $relation, $subRelation, $closure);\n\n        // 关联模型\n        if (!isset($data[$result->$localKey])) {\n            $relationModel = null;\n        } else {\n            $relationModel = $data[$result->$localKey];\n            $relationModel->setParent(clone $result);\n            $relationModel->isUpdate(true);\n            if (!empty($this->bindAttr)) {\n                // 绑定关联属性\n                $this->bindAttr($relationModel, $result, $this->bindAttr);\n            }\n        }\n\n        $result->setRelation(Loader::parseName($relation), $relationModel);\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/relation/MorphMany.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model\\relation;\n\nuse think\\db\\Query;\nuse think\\Exception;\nuse think\\Loader;\nuse think\\Model;\nuse think\\model\\Relation;\n\nclass MorphMany extends Relation\n{\n    // 多态字段\n    protected $morphKey;\n    protected $morphType;\n    // 多态类型\n    protected $type;\n\n    /**\n     * 构造函数\n     * @access public\n     * @param Model  $parent    上级模型对象\n     * @param string $model     模型名\n     * @param string $morphKey  关联外键\n     * @param string $morphType 多态字段名\n     * @param string $type      多态类型\n     */\n    public function __construct(Model $parent, $model, $morphKey, $morphType, $type)\n    {\n        $this->parent    = $parent;\n        $this->model     = $model;\n        $this->type      = $type;\n        $this->morphKey  = $morphKey;\n        $this->morphType = $morphType;\n        $this->query     = (new $model)->db();\n    }\n\n    /**\n     * 延迟获取关联数据\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包查询条件\n     * @return false|\\PDOStatement|string|\\think\\Collection\n     */\n    public function getRelation($subRelation = '', $closure = null)\n    {\n        if ($closure) {\n            call_user_func_array($closure, [ & $this->query]);\n        }\n        $list   = $this->relation($subRelation)->select();\n        $parent = clone $this->parent;\n\n        foreach ($list as &$model) {\n            $model->setParent($parent);\n        }\n\n        return $list;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param string  $operator 比较操作符\n     * @param integer $count    个数\n     * @param string  $id       关联表的统计字段\n     * @param string  $joinType JOIN类型\n     * @return Query\n     */\n    public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')\n    {\n        throw new Exception('relation not support: has');\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param mixed $where 查询条件（数组或者闭包）\n     * @return Query\n     */\n    public function hasWhere($where = [])\n    {\n        throw new Exception('relation not support: hasWhere');\n    }\n\n    /**\n     * 预载入关联查询\n     * @access public\n     * @param array    $resultSet   数据集\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)\n    {\n        $morphType = $this->morphType;\n        $morphKey  = $this->morphKey;\n        $type      = $this->type;\n        $range     = [];\n        foreach ($resultSet as $result) {\n            $pk = $result->getPk();\n            // 获取关联外键列表\n            if (isset($result->$pk)) {\n                $range[] = $result->$pk;\n            }\n        }\n\n        if (!empty($range)) {\n            $data = $this->eagerlyMorphToMany([\n                $morphKey  => ['in', $range],\n                $morphType => $type,\n            ], $relation, $subRelation, $closure);\n            // 关联属性名\n            $attr = Loader::parseName($relation);\n            // 关联数据封装\n            foreach ($resultSet as $result) {\n                if (!isset($data[$result->$pk])) {\n                    $data[$result->$pk] = [];\n                }\n                foreach ($data[$result->$pk] as &$relationModel) {\n                    $relationModel->setParent(clone $result);\n                    $relationModel->isUpdate(true);\n                }\n                $result->setRelation($attr, $this->resultSetBuild($data[$result->$pk]));\n            }\n        }\n    }\n\n    /**\n     * 预载入关联查询\n     * @access public\n     * @param Model    $result      数据对象\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResult(&$result, $relation, $subRelation, $closure)\n    {\n        $pk = $result->getPk();\n        if (isset($result->$pk)) {\n            $data = $this->eagerlyMorphToMany([\n                $this->morphKey  => $result->$pk,\n                $this->morphType => $this->type,\n            ], $relation, $subRelation, $closure);\n\n            if (!isset($data[$result->$pk])) {\n                $data[$result->$pk] = [];\n            }\n\n            foreach ($data[$result->$pk] as &$relationModel) {\n                $relationModel->setParent(clone $result);\n                $relationModel->isUpdate(true);\n            }\n\n            $result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$result->$pk]));\n        }\n    }\n\n    /**\n     * 关联统计\n     * @access public\n     * @param Model    $result  数据对象\n     * @param \\Closure $closure 闭包\n     * @return integer\n     */\n    public function relationCount($result, $closure)\n    {\n        $pk    = $result->getPk();\n        $count = 0;\n        if (isset($result->$pk)) {\n            if ($closure) {\n                call_user_func_array($closure, [ & $this->query]);\n            }\n            $count = $this->query->where([$this->morphKey => $result->$pk, $this->morphType => $this->type])->count();\n        }\n        return $count;\n    }\n\n    /**\n     * 获取关联统计子查询\n     * @access public\n     * @param \\Closure $closure 闭包\n     * @return string\n     */\n    public function getRelationCountQuery($closure)\n    {\n        if ($closure) {\n            call_user_func_array($closure, [ & $this->query]);\n        }\n\n        return $this->query->where([\n            $this->morphKey  => [\n                'exp',\n                '=' . $this->parent->getTable() . '.' . $this->parent->getPk(),\n            ],\n            $this->morphType => $this->type,\n        ])->fetchSql()->count();\n    }\n\n    /**\n     * 多态一对多 关联模型预查询\n     * @access   public\n     * @param array         $where       关联预查询条件\n     * @param string        $relation    关联名\n     * @param string        $subRelation 子关联\n     * @param bool|\\Closure $closure     闭包\n     * @return array\n     */\n    protected function eagerlyMorphToMany($where, $relation, $subRelation = '', $closure = false)\n    {\n        // 预载入关联查询 支持嵌套预载入\n        if ($closure) {\n            call_user_func_array($closure, [ & $this]);\n        }\n        $list     = $this->query->where($where)->with($subRelation)->select();\n        $morphKey = $this->morphKey;\n        // 组装模型数据\n        $data = [];\n        foreach ($list as $set) {\n            $data[$set->$morphKey][] = $set;\n        }\n        return $data;\n    }\n\n    /**\n     * 保存（新增）当前关联数据对象\n     * @access public\n     * @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键\n     * @return Model|false\n     */\n    public function save($data)\n    {\n        if ($data instanceof Model) {\n            $data = $data->getData();\n        }\n        // 保存关联表数据\n        $pk = $this->parent->getPk();\n\n        $model                  = new $this->model;\n        $data[$this->morphKey]  = $this->parent->$pk;\n        $data[$this->morphType] = $this->type;\n        return $model->save($data) ? $model : false;\n    }\n\n    /**\n     * 批量保存当前关联数据对象\n     * @access public\n     * @param array $dataSet 数据集\n     * @return integer\n     */\n    public function saveAll(array $dataSet)\n    {\n        $result = false;\n        foreach ($dataSet as $key => $data) {\n            $result = $this->save($data);\n        }\n        return $result;\n    }\n\n    /**\n     * 执行基础查询（进执行一次）\n     * @access protected\n     * @return void\n     */\n    protected function baseQuery()\n    {\n        if (empty($this->baseQuery) && $this->parent->getData()) {\n            $pk                    = $this->parent->getPk();\n            $map[$this->morphKey]  = $this->parent->$pk;\n            $map[$this->morphType] = $this->type;\n            $this->query->where($map);\n            $this->baseQuery = true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/relation/MorphOne.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model\\relation;\n\nuse think\\db\\Query;\nuse think\\Exception;\nuse think\\Loader;\nuse think\\Model;\nuse think\\model\\Relation;\n\nclass MorphOne extends Relation\n{\n    // 多态字段\n    protected $morphKey;\n    protected $morphType;\n    // 多态类型\n    protected $type;\n\n    /**\n     * 构造函数\n     * @access public\n     * @param Model  $parent    上级模型对象\n     * @param string $model     模型名\n     * @param string $morphKey  关联外键\n     * @param string $morphType 多态字段名\n     * @param string $type      多态类型\n     */\n    public function __construct(Model $parent, $model, $morphKey, $morphType, $type)\n    {\n        $this->parent    = $parent;\n        $this->model     = $model;\n        $this->type      = $type;\n        $this->morphKey  = $morphKey;\n        $this->morphType = $morphType;\n        $this->query     = (new $model)->db();\n    }\n\n    /**\n     * 延迟获取关联数据\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包查询条件\n     * @return false|\\PDOStatement|string|\\think\\Collection\n     */\n    public function getRelation($subRelation = '', $closure = null)\n    {\n        if ($closure) {\n            call_user_func_array($closure, [ & $this->query]);\n        }\n        $relationModel = $this->relation($subRelation)->find();\n\n        if ($relationModel) {\n            $relationModel->setParent(clone $this->parent);\n        }\n\n        return $relationModel;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param string  $operator 比较操作符\n     * @param integer $count    个数\n     * @param string  $id       关联表的统计字段\n     * @param string  $joinType JOIN类型\n     * @return Query\n     */\n    public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')\n    {\n        return $this->parent;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param mixed $where 查询条件（数组或者闭包）\n     * @return Query\n     */\n    public function hasWhere($where = [])\n    {\n        throw new Exception('relation not support: hasWhere');\n    }\n\n    /**\n     * 预载入关联查询\n     * @access public\n     * @param array    $resultSet   数据集\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)\n    {\n        $morphType = $this->morphType;\n        $morphKey  = $this->morphKey;\n        $type      = $this->type;\n        $range     = [];\n        foreach ($resultSet as $result) {\n            $pk = $result->getPk();\n            // 获取关联外键列表\n            if (isset($result->$pk)) {\n                $range[] = $result->$pk;\n            }\n        }\n\n        if (!empty($range)) {\n            $data = $this->eagerlyMorphToOne([\n                $morphKey  => ['in', $range],\n                $morphType => $type,\n            ], $relation, $subRelation, $closure);\n            // 关联属性名\n            $attr = Loader::parseName($relation);\n            // 关联数据封装\n            foreach ($resultSet as $result) {\n                if (!isset($data[$result->$pk])) {\n                    $relationModel = null;\n                } else {\n                    $relationModel = $data[$result->$pk];\n                    $relationModel->setParent(clone $result);\n                    $relationModel->isUpdate(true);\n                }\n\n                $result->setRelation($attr, $relationModel);\n            }\n        }\n    }\n\n    /**\n     * 预载入关联查询\n     * @access public\n     * @param Model    $result      数据对象\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResult(&$result, $relation, $subRelation, $closure)\n    {\n        $pk = $result->getPk();\n        if (isset($result->$pk)) {\n            $pk   = $result->$pk;\n            $data = $this->eagerlyMorphToOne([\n                $this->morphKey  => $pk,\n                $this->morphType => $this->type,\n            ], $relation, $subRelation, $closure);\n\n            if (isset($data[$pk])) {\n                $relationModel = $data[$pk];\n                $relationModel->setParent(clone $result);\n                $relationModel->isUpdate(true);\n            } else {\n                $relationModel = null;\n            }\n\n            $result->setRelation(Loader::parseName($relation), $relationModel);\n        }\n    }\n\n    /**\n     * 多态一对一 关联模型预查询\n     * @access   public\n     * @param array         $where       关联预查询条件\n     * @param string        $relation    关联名\n     * @param string        $subRelation 子关联\n     * @param bool|\\Closure $closure     闭包\n     * @return array\n     */\n    protected function eagerlyMorphToOne($where, $relation, $subRelation = '', $closure = false)\n    {\n        // 预载入关联查询 支持嵌套预载入\n        if ($closure) {\n            call_user_func_array($closure, [ & $this]);\n        }\n        $list     = $this->query->where($where)->with($subRelation)->find();\n        $morphKey = $this->morphKey;\n        // 组装模型数据\n        $data = [];\n        foreach ($list as $set) {\n            $data[$set->$morphKey][] = $set;\n        }\n        return $data;\n    }\n\n    /**\n     * 保存（新增）当前关联数据对象\n     * @access public\n     * @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键\n     * @return Model|false\n     */\n    public function save($data)\n    {\n        if ($data instanceof Model) {\n            $data = $data->getData();\n        }\n        // 保存关联表数据\n        $pk = $this->parent->getPk();\n\n        $model                  = new $this->model;\n        $data[$this->morphKey]  = $this->parent->$pk;\n        $data[$this->morphType] = $this->type;\n        return $model->save($data) ? $model : false;\n    }\n\n    /**\n     * 执行基础查询（进执行一次）\n     * @access protected\n     * @return void\n     */\n    protected function baseQuery()\n    {\n        if (empty($this->baseQuery) && $this->parent->getData()) {\n            $pk                    = $this->parent->getPk();\n            $map[$this->morphKey]  = $this->parent->$pk;\n            $map[$this->morphType] = $this->type;\n            $this->query->where($map);\n            $this->baseQuery = true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/relation/MorphTo.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model\\relation;\n\nuse think\\Exception;\nuse think\\Loader;\nuse think\\Model;\nuse think\\model\\Relation;\n\nclass MorphTo extends Relation\n{\n    // 多态字段\n    protected $morphKey;\n    protected $morphType;\n    // 多态别名\n    protected $alias;\n    protected $relation;\n\n    /**\n     * 构造函数\n     * @access public\n     * @param Model  $parent    上级模型对象\n     * @param string $morphType 多态字段名\n     * @param string $morphKey  外键名\n     * @param array  $alias     多态别名定义\n     * @param string $relation  关联名\n     */\n    public function __construct(Model $parent, $morphType, $morphKey, $alias = [], $relation = null)\n    {\n        $this->parent    = $parent;\n        $this->morphType = $morphType;\n        $this->morphKey  = $morphKey;\n        $this->alias     = $alias;\n        $this->relation  = $relation;\n    }\n\n    /**\n     * 延迟获取关联数据\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包查询条件\n     * @return mixed\n     */\n    public function getRelation($subRelation = '', $closure = null)\n    {\n        $morphKey  = $this->morphKey;\n        $morphType = $this->morphType;\n        // 多态模型\n        $model = $this->parseModel($this->parent->$morphType);\n        // 主键数据\n        $pk            = $this->parent->$morphKey;\n        $relationModel = (new $model)->relation($subRelation)->find($pk);\n\n        if ($relationModel) {\n            $relationModel->setParent(clone $this->parent);\n        }\n        return $relationModel;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param string  $operator 比较操作符\n     * @param integer $count    个数\n     * @param string  $id       关联表的统计字段\n     * @param string  $joinType JOIN类型\n     * @return Query\n     */\n    public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')\n    {\n        return $this->parent;\n    }\n\n    /**\n     * 根据关联条件查询当前模型\n     * @access public\n     * @param mixed $where 查询条件（数组或者闭包）\n     * @return Query\n     */\n    public function hasWhere($where = [])\n    {\n        throw new Exception('relation not support: hasWhere');\n    }\n\n    /**\n     * 解析模型的完整命名空间\n     * @access public\n     * @param string $model 模型名（或者完整类名）\n     * @return string\n     */\n    protected function parseModel($model)\n    {\n        if (isset($this->alias[$model])) {\n            $model = $this->alias[$model];\n        }\n        if (false === strpos($model, '\\\\')) {\n            $path = explode('\\\\', get_class($this->parent));\n            array_pop($path);\n            array_push($path, Loader::parseName($model, 1));\n            $model = implode('\\\\', $path);\n        }\n        return $model;\n    }\n\n    /**\n     * 设置多态别名\n     * @access public\n     * @param array $alias 别名定义\n     * @return $this\n     */\n    public function setAlias($alias)\n    {\n        $this->alias = $alias;\n        return $this;\n    }\n\n    /**\n     * 移除关联查询参数\n     * @access public\n     * @return $this\n     */\n    public function removeOption()\n    {\n        return $this;\n    }\n\n    /**\n     * 预载入关联查询\n     * @access public\n     * @param array    $resultSet   数据集\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     * @throws Exception\n     */\n    public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)\n    {\n        $morphKey  = $this->morphKey;\n        $morphType = $this->morphType;\n        $range     = [];\n        foreach ($resultSet as $result) {\n            // 获取关联外键列表\n            if (!empty($result->$morphKey)) {\n                $range[$result->$morphType][] = $result->$morphKey;\n            }\n        }\n\n        if (!empty($range)) {\n            // 关联属性名\n            $attr = Loader::parseName($relation);\n            foreach ($range as $key => $val) {\n                // 多态类型映射\n                $model = $this->parseModel($key);\n                $obj   = new $model;\n                $pk    = $obj->getPk();\n                $list  = $obj->all($val, $subRelation);\n                $data  = [];\n                foreach ($list as $k => $vo) {\n                    $data[$vo->$pk] = $vo;\n                }\n                foreach ($resultSet as $result) {\n                    if ($key == $result->$morphType) {\n                        // 关联模型\n                        if (!isset($data[$result->$morphKey])) {\n                            throw new Exception('relation data not exists :' . $this->model);\n                        } else {\n                            $relationModel = $data[$result->$morphKey];\n                            $relationModel->setParent(clone $result);\n                            $relationModel->isUpdate(true);\n\n                            $result->setRelation($attr, $relationModel);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 预载入关联查询\n     * @access public\n     * @param Model    $result      数据对象\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResult(&$result, $relation, $subRelation, $closure)\n    {\n        $morphKey  = $this->morphKey;\n        $morphType = $this->morphType;\n        // 多态类型映射\n        $model = $this->parseModel($result->{$this->morphType});\n        $this->eagerlyMorphToOne($model, $relation, $result, $subRelation);\n    }\n\n    /**\n     * 关联统计\n     * @access public\n     * @param Model    $result  数据对象\n     * @param \\Closure $closure 闭包\n     * @return integer\n     */\n    public function relationCount($result, $closure)\n    {\n    }\n\n    /**\n     * 多态MorphTo 关联模型预查询\n     * @access   public\n     * @param object $model       关联模型对象\n     * @param string $relation    关联名\n     * @param        $result\n     * @param string $subRelation 子关联\n     * @return void\n     */\n    protected function eagerlyMorphToOne($model, $relation, &$result, $subRelation = '')\n    {\n        // 预载入关联查询 支持嵌套预载入\n        $pk   = $this->parent->{$this->morphKey};\n        $data = (new $model)->with($subRelation)->find($pk);\n        if ($data) {\n            $data->setParent(clone $result);\n            $data->isUpdate(true);\n        }\n        $result->setRelation(Loader::parseName($relation), $data ?: null);\n    }\n\n    /**\n     * 添加关联数据\n     * @access public\n     * @param Model $model       关联模型对象\n     * @return Model\n     */\n    public function associate($model)\n    {\n        $morphKey  = $this->morphKey;\n        $morphType = $this->morphType;\n        $pk        = $model->getPk();\n\n        $this->parent->setAttr($morphKey, $model->$pk);\n        $this->parent->setAttr($morphType, get_class($model));\n        $this->parent->save();\n\n        return $this->parent->setRelation($this->relation, $model);\n    }\n\n    /**\n     * 注销关联数据\n     * @access public\n     * @return Model\n     */\n    public function dissociate()\n    {\n        $morphKey  = $this->morphKey;\n        $morphType = $this->morphType;\n\n        $this->parent->setAttr($morphKey, null);\n        $this->parent->setAttr($morphType, null);\n        $this->parent->save();\n\n        return $this->parent->setRelation($this->relation, null);\n    }\n\n    /**\n     * 执行基础查询（进执行一次）\n     * @access protected\n     * @return void\n     */\n    protected function baseQuery()\n    {}\n}\n"
  },
  {
    "path": "thinkphp/library/think/model/relation/OneToOne.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\model\\relation;\n\nuse think\\db\\Query;\nuse think\\Exception;\nuse think\\Loader;\nuse think\\Model;\nuse think\\model\\Relation;\n\n/**\n * Class OneToOne\n * @package think\\model\\relation\n *\n */\nabstract class OneToOne extends Relation\n{\n    // 预载入方式 0 -JOIN 1 -IN\n    protected $eagerlyType = 1;\n    // 当前关联的JOIN类型\n    protected $joinType;\n    // 要绑定的属性\n    protected $bindAttr = [];\n    // 关联方法名\n    protected $relation;\n\n    /**\n     * 设置join类型\n     * @access public\n     * @param string $type JOIN类型\n     * @return $this\n     */\n    public function joinType($type)\n    {\n        $this->joinType = $type;\n        return $this;\n    }\n\n    /**\n     * 预载入关联查询（JOIN方式）\n     * @access public\n     * @param Query    $query       查询对象\n     * @param string   $relation    关联名\n     * @param string   $subRelation 子关联\n     * @param \\Closure $closure     闭包条件\n     * @param bool     $first\n     * @return void\n     */\n    public function eagerly(Query $query, $relation, $subRelation, $closure, $first)\n    {\n        $name  = Loader::parseName(basename(str_replace('\\\\', '/', $query->getModel())));\n        $alias = $name;\n        if ($first) {\n            $table = $query->getTable();\n            $query->table([$table => $alias]);\n            if ($query->getOptions('field')) {\n                $field = $query->getOptions('field');\n                $query->removeOption('field');\n            } else {\n                $field = true;\n            }\n            $query->field($field, false, $table, $alias);\n            $field = null;\n        }\n\n        // 预载入封装\n        $joinTable = $this->query->getTable();\n        $joinAlias = $relation;\n        $query->via($joinAlias);\n\n        if ($this instanceof BelongsTo) {\n            $query->join($joinTable . ' ' . $joinAlias, $alias . '.' . $this->foreignKey . '=' . $joinAlias . '.' . $this->localKey, $this->joinType);\n        } else {\n            $query->join($joinTable . ' ' . $joinAlias, $alias . '.' . $this->localKey . '=' . $joinAlias . '.' . $this->foreignKey, $this->joinType);\n        }\n\n        if ($closure) {\n            // 执行闭包查询\n            call_user_func_array($closure, [ & $query]);\n            // 使用withField指定获取关联的字段，如\n            // $query->where(['id'=>1])->withField('id,name');\n            if ($query->getOptions('with_field')) {\n                $field = $query->getOptions('with_field');\n                $query->removeOption('with_field');\n            }\n        } elseif (isset($this->option['field'])) {\n            $field = $this->option['field'];\n        }\n        $query->field(isset($field) ? $field : true, false, $joinTable, $joinAlias, $relation . '__');\n    }\n\n    /**\n     *  预载入关联查询（数据集）\n     * @param array    $resultSet\n     * @param string   $relation\n     * @param string   $subRelation\n     * @param \\Closure $closure\n     * @return mixed\n     */\n    abstract protected function eagerlySet(&$resultSet, $relation, $subRelation, $closure);\n\n    /**\n     * 预载入关联查询（数据）\n     * @param Model    $result\n     * @param string   $relation\n     * @param string   $subRelation\n     * @param \\Closure $closure\n     * @return mixed\n     */\n    abstract protected function eagerlyOne(&$result, $relation, $subRelation, $closure);\n\n    /**\n     * 预载入关联查询（数据集）\n     * @access public\n     * @param array    $resultSet   数据集\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)\n    {\n        if (1 == $this->eagerlyType) {\n            // IN查询\n            $this->eagerlySet($resultSet, $relation, $subRelation, $closure);\n        } else {\n            // 模型关联组装\n            foreach ($resultSet as $result) {\n                $this->match($this->model, $relation, $result);\n            }\n        }\n    }\n\n    /**\n     * 预载入关联查询（数据）\n     * @access public\n     * @param Model    $result      数据对象\n     * @param string   $relation    当前关联名\n     * @param string   $subRelation 子关联名\n     * @param \\Closure $closure     闭包\n     * @return void\n     */\n    public function eagerlyResult(&$result, $relation, $subRelation, $closure)\n    {\n        if (1 == $this->eagerlyType) {\n            // IN查询\n            $this->eagerlyOne($result, $relation, $subRelation, $closure);\n        } else {\n            // 模型关联组装\n            $this->match($this->model, $relation, $result);\n        }\n    }\n\n    /**\n     * 保存（新增）当前关联数据对象\n     * @access public\n     * @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键\n     * @return Model|false\n     */\n    public function save($data)\n    {\n        if ($data instanceof Model) {\n            $data = $data->getData();\n        }\n        $model = new $this->model;\n        // 保存关联表数据\n        $data[$this->foreignKey] = $this->parent->{$this->localKey};\n        return $model->save($data) ? $model : false;\n    }\n\n    /**\n     * 设置预载入方式\n     * @access public\n     * @param integer $type 预载入方式 0 JOIN查询 1 IN查询\n     * @return $this\n     */\n    public function setEagerlyType($type)\n    {\n        $this->eagerlyType = $type;\n        return $this;\n    }\n\n    /**\n     * 获取预载入方式\n     * @access public\n     * @return integer\n     */\n    public function getEagerlyType()\n    {\n        return $this->eagerlyType;\n    }\n\n    /**\n     * 绑定关联表的属性到父模型属性\n     * @access public\n     * @param mixed $attr 要绑定的属性列表\n     * @return $this\n     */\n    public function bind($attr)\n    {\n        if (is_string($attr)) {\n            $attr = explode(',', $attr);\n        }\n        $this->bindAttr = $attr;\n        return $this;\n    }\n\n    /**\n     * 关联统计\n     * @access public\n     * @param Model    $result  数据对象\n     * @param \\Closure $closure 闭包\n     * @return integer\n     */\n    public function relationCount($result, $closure)\n    {\n    }\n\n    /**\n     * 一对一 关联模型预查询拼装\n     * @access public\n     * @param string $model    模型名称\n     * @param string $relation 关联名\n     * @param Model  $result   模型对象实例\n     * @return void\n     */\n    protected function match($model, $relation, &$result)\n    {\n        // 重新组装模型数据\n        foreach ($result->getData() as $key => $val) {\n            if (strpos($key, '__')) {\n                list($name, $attr) = explode('__', $key, 2);\n                if ($name == $relation) {\n                    $list[$name][$attr] = $val;\n                    unset($result->$key);\n                }\n            }\n        }\n\n        if (isset($list[$relation])) {\n            $relationModel = new $model($list[$relation]);\n            $relationModel->setParent(clone $result);\n            $relationModel->isUpdate(true);\n\n            if (!empty($this->bindAttr)) {\n                $this->bindAttr($relationModel, $result, $this->bindAttr);\n            }\n        } else {\n            $relationModel = null;\n        }\n        $result->setRelation(Loader::parseName($relation), $relationModel);\n    }\n\n    /**\n     * 绑定关联属性到父模型\n     * @access protected\n     * @param Model $model    关联模型对象\n     * @param Model $result   父模型对象\n     * @param array $bindAttr 绑定属性\n     * @return void\n     * @throws Exception\n     */\n    protected function bindAttr($model, &$result, $bindAttr)\n    {\n        foreach ($bindAttr as $key => $attr) {\n            $key = is_numeric($key) ? $attr : $key;\n            if (isset($result->$key)) {\n                throw new Exception('bind attr has exists:' . $key);\n            } else {\n                $result->setAttr($key, $model->$attr);\n            }\n        }\n    }\n\n    /**\n     * 一对一 关联模型预查询（IN方式）\n     * @access public\n     * @param object        $model       关联模型对象\n     * @param array         $where       关联预查询条件\n     * @param string        $key         关联键名\n     * @param string        $relation    关联名\n     * @param string        $subRelation 子关联\n     * @param bool|\\Closure $closure\n     * @return array\n     */\n    protected function eagerlyWhere($model, $where, $key, $relation, $subRelation = '', $closure = false)\n    {\n        // 预载入关联查询 支持嵌套预载入\n        if ($closure) {\n            call_user_func_array($closure, [ & $model]);\n            if ($field = $model->getOptions('with_field')) {\n                $model->field($field)->removeOption('with_field');\n            }\n        }\n        $list = $model->where($where)->with($subRelation)->select();\n\n        // 组装模型数据\n        $data = [];\n        foreach ($list as $set) {\n            $data[$set->$key] = $set;\n        }\n        return $data;\n    }\n\n    /**\n     * 执行基础查询（进执行一次）\n     * @access protected\n     * @return void\n     */\n    protected function baseQuery()\n    {}\n}\n"
  },
  {
    "path": "thinkphp/library/think/paginator/driver/Bootstrap.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: zhangyajun <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\paginator\\driver;\n\nuse think\\Paginator;\n\nclass Bootstrap extends Paginator\n{\n\n    /**\n     * 上一页按钮\n     * @param string $text\n     * @return string\n     */\n    protected function getPreviousButton($text = \"&laquo;\")\n    {\n\n        if ($this->currentPage() <= 1) {\n            return $this->getDisabledTextWrapper($text);\n        }\n\n        $url = $this->url(\n            $this->currentPage() - 1\n        );\n\n        return $this->getPageLinkWrapper($url, $text);\n    }\n\n    /**\n     * 下一页按钮\n     * @param string $text\n     * @return string\n     */\n    protected function getNextButton($text = '&raquo;')\n    {\n        if (!$this->hasMore) {\n            return $this->getDisabledTextWrapper($text);\n        }\n\n        $url = $this->url($this->currentPage() + 1);\n\n        return $this->getPageLinkWrapper($url, $text);\n    }\n\n    /**\n     * 页码按钮\n     * @return string\n     */\n    protected function getLinks()\n    {\n        if ($this->simple)\n            return '';\n\n        $block = [\n            'first'  => null,\n            'slider' => null,\n            'last'   => null\n        ];\n\n        $side   = 3;\n        $window = $side * 2;\n\n        if ($this->lastPage < $window + 6) {\n            $block['first'] = $this->getUrlRange(1, $this->lastPage);\n        } elseif ($this->currentPage <= $window) {\n            $block['first'] = $this->getUrlRange(1, $window + 2);\n            $block['last']  = $this->getUrlRange($this->lastPage - 1, $this->lastPage);\n        } elseif ($this->currentPage > ($this->lastPage - $window)) {\n            $block['first'] = $this->getUrlRange(1, 2);\n            $block['last']  = $this->getUrlRange($this->lastPage - ($window + 2), $this->lastPage);\n        } else {\n            $block['first']  = $this->getUrlRange(1, 2);\n            $block['slider'] = $this->getUrlRange($this->currentPage - $side, $this->currentPage + $side);\n            $block['last']   = $this->getUrlRange($this->lastPage - 1, $this->lastPage);\n        }\n\n        $html = '';\n\n        if (is_array($block['first'])) {\n            $html .= $this->getUrlLinks($block['first']);\n        }\n\n        if (is_array($block['slider'])) {\n            $html .= $this->getDots();\n            $html .= $this->getUrlLinks($block['slider']);\n        }\n\n        if (is_array($block['last'])) {\n            $html .= $this->getDots();\n            $html .= $this->getUrlLinks($block['last']);\n        }\n\n        return $html;\n    }\n\n    /**\n     * 渲染分页html\n     * @return mixed\n     */\n    public function render()\n    {\n        if ($this->hasPages()) {\n            if ($this->simple) {\n                return sprintf(\n                    '<ul class=\"pager\">%s %s</ul>',\n                    $this->getPreviousButton(),\n                    $this->getNextButton()\n                );\n            } else {\n                return sprintf(\n                    '<ul class=\"pagination\">%s %s %s</ul>',\n                    $this->getPreviousButton(),\n                    $this->getLinks(),\n                    $this->getNextButton()\n                );\n            }\n        }\n    }\n\n    /**\n     * 生成一个可点击的按钮\n     *\n     * @param  string $url\n     * @param  int    $page\n     * @return string\n     */\n    protected function getAvailablePageWrapper($url, $page)\n    {\n        return '<li><a href=\"' . htmlentities($url) . '\">' . $page . '</a></li>';\n    }\n\n    /**\n     * 生成一个禁用的按钮\n     *\n     * @param  string $text\n     * @return string\n     */\n    protected function getDisabledTextWrapper($text)\n    {\n        return '<li class=\"disabled\"><span>' . $text . '</span></li>';\n    }\n\n    /**\n     * 生成一个激活的按钮\n     *\n     * @param  string $text\n     * @return string\n     */\n    protected function getActivePageWrapper($text)\n    {\n        return '<li class=\"active\"><span>' . $text . '</span></li>';\n    }\n\n    /**\n     * 生成省略号按钮\n     *\n     * @return string\n     */\n    protected function getDots()\n    {\n        return $this->getDisabledTextWrapper('...');\n    }\n\n    /**\n     * 批量生成页码按钮.\n     *\n     * @param  array $urls\n     * @return string\n     */\n    protected function getUrlLinks(array $urls)\n    {\n        $html = '';\n\n        foreach ($urls as $page => $url) {\n            $html .= $this->getPageLinkWrapper($url, $page);\n        }\n\n        return $html;\n    }\n\n    /**\n     * 生成普通页码按钮\n     *\n     * @param  string $url\n     * @param  int    $page\n     * @return string\n     */\n    protected function getPageLinkWrapper($url, $page)\n    {\n        if ($page == $this->currentPage()) {\n            return $this->getActivePageWrapper($page);\n        }\n\n        return $this->getAvailablePageWrapper($url, $page);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/process/Builder.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\process;\n\nuse think\\Process;\n\nclass Builder\n{\n    private $arguments;\n    private $cwd;\n    private $env = null;\n    private $input;\n    private $timeout        = 60;\n    private $options        = [];\n    private $inheritEnv     = true;\n    private $prefix         = [];\n    private $outputDisabled = false;\n\n    /**\n     * 构造方法\n     * @param string[] $arguments 参数\n     */\n    public function __construct(array $arguments = [])\n    {\n        $this->arguments = $arguments;\n    }\n\n    /**\n     * 创建一个实例\n     * @param string[] $arguments 参数\n     * @return self\n     */\n    public static function create(array $arguments = [])\n    {\n        return new static($arguments);\n    }\n\n    /**\n     * 添加一个参数\n     * @param string $argument 参数\n     * @return self\n     */\n    public function add($argument)\n    {\n        $this->arguments[] = $argument;\n\n        return $this;\n    }\n\n    /**\n     * 添加一个前缀\n     * @param string|array $prefix\n     * @return self\n     */\n    public function setPrefix($prefix)\n    {\n        $this->prefix = is_array($prefix) ? $prefix : [$prefix];\n\n        return $this;\n    }\n\n    /**\n     * 设置参数\n     * @param string[] $arguments\n     * @return  self\n     */\n    public function setArguments(array $arguments)\n    {\n        $this->arguments = $arguments;\n\n        return $this;\n    }\n\n    /**\n     * 设置工作目录\n     * @param null|string $cwd\n     * @return  self\n     */\n    public function setWorkingDirectory($cwd)\n    {\n        $this->cwd = $cwd;\n\n        return $this;\n    }\n\n    /**\n     * 是否初始化环境变量\n     * @param bool $inheritEnv\n     * @return self\n     */\n    public function inheritEnvironmentVariables($inheritEnv = true)\n    {\n        $this->inheritEnv = $inheritEnv;\n\n        return $this;\n    }\n\n    /**\n     * 设置环境变量\n     * @param string      $name\n     * @param null|string $value\n     * @return self\n     */\n    public function setEnv($name, $value)\n    {\n        $this->env[$name] = $value;\n\n        return $this;\n    }\n\n    /**\n     *  添加环境变量\n     * @param array $variables\n     * @return self\n     */\n    public function addEnvironmentVariables(array $variables)\n    {\n        $this->env = array_replace($this->env, $variables);\n\n        return $this;\n    }\n\n    /**\n     * 设置输入\n     * @param mixed $input\n     * @return self\n     */\n    public function setInput($input)\n    {\n        $this->input = Utils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input);\n\n        return $this;\n    }\n\n    /**\n     * 设置超时时间\n     * @param float|null $timeout\n     * @return self\n     */\n    public function setTimeout($timeout)\n    {\n        if (null === $timeout) {\n            $this->timeout = null;\n\n            return $this;\n        }\n\n        $timeout = (float) $timeout;\n\n        if ($timeout < 0) {\n            throw new \\InvalidArgumentException('The timeout value must be a valid positive integer or float number.');\n        }\n\n        $this->timeout = $timeout;\n\n        return $this;\n    }\n\n    /**\n     * 设置proc_open选项\n     * @param string $name\n     * @param string $value\n     * @return self\n     */\n    public function setOption($name, $value)\n    {\n        $this->options[$name] = $value;\n\n        return $this;\n    }\n\n    /**\n     * 禁止输出\n     * @return self\n     */\n    public function disableOutput()\n    {\n        $this->outputDisabled = true;\n\n        return $this;\n    }\n\n    /**\n     * 开启输出\n     * @return self\n     */\n    public function enableOutput()\n    {\n        $this->outputDisabled = false;\n\n        return $this;\n    }\n\n    /**\n     * 创建一个Process实例\n     * @return Process\n     */\n    public function getProcess()\n    {\n        if (0 === count($this->prefix) && 0 === count($this->arguments)) {\n            throw new \\LogicException('You must add() command arguments before calling getProcess().');\n        }\n\n        $options = $this->options;\n\n        $arguments = array_merge($this->prefix, $this->arguments);\n        $script    = implode(' ', array_map([__NAMESPACE__ . '\\\\Utils', 'escapeArgument'], $arguments));\n\n        if ($this->inheritEnv) {\n            // include $_ENV for BC purposes\n            $env = array_replace($_ENV, $_SERVER, $this->env);\n        } else {\n            $env = $this->env;\n        }\n\n        $process = new Process($script, $this->cwd, $env, $this->input, $this->timeout, $options);\n\n        if ($this->outputDisabled) {\n            $process->disableOutput();\n        }\n\n        return $process;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/process/Utils.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | TopThink [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2015 http://www.topthink.com All rights reserved.\n// +----------------------------------------------------------------------\n// | Author: zhangyajun <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\process;\n\nclass Utils\n{\n\n    /**\n     * 转义字符串\n     * @param string $argument\n     * @return string\n     */\n    public static function escapeArgument($argument)\n    {\n\n        if ('' === $argument) {\n            return escapeshellarg($argument);\n        }\n        $escapedArgument = '';\n        $quote           = false;\n        foreach (preg_split('/(\")/i', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {\n            if ('\"' === $part) {\n                $escapedArgument .= '\\\\\"';\n            } elseif (self::isSurroundedBy($part, '%')) {\n                // Avoid environment variable expansion\n                $escapedArgument .= '^%\"' . substr($part, 1, -1) . '\"^%';\n            } else {\n                // escape trailing backslash\n                if ('\\\\' === substr($part, -1)) {\n                    $part .= '\\\\';\n                }\n                $quote = true;\n                $escapedArgument .= $part;\n            }\n        }\n        if ($quote) {\n            $escapedArgument = '\"' . $escapedArgument . '\"';\n        }\n        return $escapedArgument;\n    }\n\n    /**\n     * 验证并进行规范化Process输入。\n     * @param string $caller\n     * @param mixed  $input\n     * @return string\n     * @throws \\InvalidArgumentException\n     */\n    public static function validateInput($caller, $input)\n    {\n        if (null !== $input) {\n            if (is_resource($input)) {\n                return $input;\n            }\n            if (is_scalar($input)) {\n                return (string) $input;\n            }\n            throw new \\InvalidArgumentException(sprintf('%s only accepts strings or stream resources.', $caller));\n        }\n        return $input;\n    }\n\n    private static function isSurroundedBy($arg, $char)\n    {\n        return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/process/exception/Failed.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\process\\exception;\n\nuse think\\Process;\n\nclass Failed extends \\RuntimeException\n{\n\n    private $process;\n\n    public function __construct(Process $process)\n    {\n        if ($process->isSuccessful()) {\n            throw new \\InvalidArgumentException('Expected a failed process, but the given process was successful.');\n        }\n\n        $error = sprintf('The command \"%s\" failed.' . \"\\nExit Code: %s(%s)\", $process->getCommandLine(), $process->getExitCode(), $process->getExitCodeText());\n\n        if (!$process->isOutputDisabled()) {\n            $error .= sprintf(\"\\n\\nOutput:\\n================\\n%s\\n\\nError Output:\\n================\\n%s\", $process->getOutput(), $process->getErrorOutput());\n        }\n\n        parent::__construct($error);\n\n        $this->process = $process;\n    }\n\n    public function getProcess()\n    {\n        return $this->process;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/process/exception/Timeout.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\process\\exception;\n\nuse think\\Process;\n\nclass Timeout extends \\RuntimeException\n{\n\n    const TYPE_GENERAL = 1;\n    const TYPE_IDLE    = 2;\n\n    private $process;\n    private $timeoutType;\n\n    public function __construct(Process $process, $timeoutType)\n    {\n        $this->process     = $process;\n        $this->timeoutType = $timeoutType;\n\n        parent::__construct(sprintf('The process \"%s\" exceeded the timeout of %s seconds.', $process->getCommandLine(), $this->getExceededTimeout()));\n    }\n\n    public function getProcess()\n    {\n        return $this->process;\n    }\n\n    public function isGeneralTimeout()\n    {\n        return $this->timeoutType === self::TYPE_GENERAL;\n    }\n\n    public function isIdleTimeout()\n    {\n        return $this->timeoutType === self::TYPE_IDLE;\n    }\n\n    public function getExceededTimeout()\n    {\n        switch ($this->timeoutType) {\n            case self::TYPE_GENERAL:\n                return $this->process->getTimeout();\n\n            case self::TYPE_IDLE:\n                return $this->process->getIdleTimeout();\n\n            default:\n                throw new \\LogicException(sprintf('Unknown timeout type \"%d\".', $this->timeoutType));\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/process/pipes/Pipes.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\process\\pipes;\n\nabstract class Pipes\n{\n\n    /** @var array */\n    public $pipes = [];\n\n    /** @var string */\n    protected $inputBuffer = '';\n    /** @var resource|null */\n    protected $input;\n\n    /** @var bool */\n    private $blocked = true;\n\n    const CHUNK_SIZE = 16384;\n\n    /**\n     * 返回用于 proc_open 描述符的数组\n     * @return array\n     */\n    abstract public function getDescriptors();\n\n    /**\n     * 返回一个数组的索引由其相关的流，以防这些管道使用的临时文件的文件名。\n     * @return string[]\n     */\n    abstract public function getFiles();\n\n    /**\n     * 文件句柄和管道中读取数据。\n     * @param bool $blocking 是否使用阻塞调用\n     * @param bool $close    是否要关闭管道，如果他们已经到达 EOF。\n     * @return string[]\n     */\n    abstract public function readAndWrite($blocking, $close = false);\n\n    /**\n     * 返回当前状态如果有打开的文件句柄或管道。\n     * @return bool\n     */\n    abstract public function areOpen();\n\n    /**\n     * {@inheritdoc}\n     */\n    public function close()\n    {\n        foreach ($this->pipes as $pipe) {\n            fclose($pipe);\n        }\n        $this->pipes = [];\n    }\n\n    /**\n     * 检查系统调用已被中断\n     * @return bool\n     */\n    protected function hasSystemCallBeenInterrupted()\n    {\n        $lastError = error_get_last();\n\n        return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call');\n    }\n\n    protected function unblock()\n    {\n        if (!$this->blocked) {\n            return;\n        }\n\n        foreach ($this->pipes as $pipe) {\n            stream_set_blocking($pipe, 0);\n        }\n        if (null !== $this->input) {\n            stream_set_blocking($this->input, 0);\n        }\n\n        $this->blocked = false;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/process/pipes/Unix.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\process\\pipes;\n\nuse think\\Process;\n\nclass Unix extends Pipes\n{\n\n    /** @var bool */\n    private $ttyMode;\n    /** @var bool */\n    private $ptyMode;\n    /** @var bool */\n    private $disableOutput;\n\n    public function __construct($ttyMode, $ptyMode, $input, $disableOutput)\n    {\n        $this->ttyMode       = (bool) $ttyMode;\n        $this->ptyMode       = (bool) $ptyMode;\n        $this->disableOutput = (bool) $disableOutput;\n\n        if (is_resource($input)) {\n            $this->input = $input;\n        } else {\n            $this->inputBuffer = (string) $input;\n        }\n    }\n\n    public function __destruct()\n    {\n        $this->close();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getDescriptors()\n    {\n        if ($this->disableOutput) {\n            $nullstream = fopen('/dev/null', 'c');\n\n            return [\n                ['pipe', 'r'],\n                $nullstream,\n                $nullstream,\n            ];\n        }\n\n        if ($this->ttyMode) {\n            return [\n                ['file', '/dev/tty', 'r'],\n                ['file', '/dev/tty', 'w'],\n                ['file', '/dev/tty', 'w'],\n            ];\n        }\n\n        if ($this->ptyMode && Process::isPtySupported()) {\n            return [\n                ['pty'],\n                ['pty'],\n                ['pty'],\n            ];\n        }\n\n        return [\n            ['pipe', 'r'],\n            ['pipe', 'w'], // stdout\n            ['pipe', 'w'], // stderr\n        ];\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getFiles()\n    {\n        return [];\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function readAndWrite($blocking, $close = false)\n    {\n\n        if (1 === count($this->pipes) && [0] === array_keys($this->pipes)) {\n            fclose($this->pipes[0]);\n            unset($this->pipes[0]);\n        }\n\n        if (empty($this->pipes)) {\n            return [];\n        }\n\n        $this->unblock();\n\n        $read = [];\n\n        if (null !== $this->input) {\n            $r = array_merge($this->pipes, ['input' => $this->input]);\n        } else {\n            $r = $this->pipes;\n        }\n\n        unset($r[0]);\n\n        $w = isset($this->pipes[0]) ? [$this->pipes[0]] : null;\n        $e = null;\n\n        if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {\n\n            if (!$this->hasSystemCallBeenInterrupted()) {\n                $this->pipes = [];\n            }\n\n            return $read;\n        }\n\n        if (0 === $n) {\n            return $read;\n        }\n\n        foreach ($r as $pipe) {\n\n            $type = (false !== $found = array_search($pipe, $this->pipes)) ? $found : 'input';\n            $data = '';\n            while ('' !== $dataread = (string) fread($pipe, self::CHUNK_SIZE)) {\n                $data .= $dataread;\n            }\n\n            if ('' !== $data) {\n                if ('input' === $type) {\n                    $this->inputBuffer .= $data;\n                } else {\n                    $read[$type] = $data;\n                }\n            }\n\n            if (false === $data || (true === $close && feof($pipe) && '' === $data)) {\n                if ('input' === $type) {\n                    $this->input = null;\n                } else {\n                    fclose($this->pipes[$type]);\n                    unset($this->pipes[$type]);\n                }\n            }\n        }\n\n        if (null !== $w && 0 < count($w)) {\n            while (strlen($this->inputBuffer)) {\n                $written = fwrite($w[0], $this->inputBuffer, 2 << 18); // write 512k\n                if ($written > 0) {\n                    $this->inputBuffer = (string) substr($this->inputBuffer, $written);\n                } else {\n                    break;\n                }\n            }\n        }\n\n        if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) {\n            fclose($this->pipes[0]);\n            unset($this->pipes[0]);\n        }\n\n        return $read;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function areOpen()\n    {\n        return (bool) $this->pipes;\n    }\n\n    /**\n     * 创建一个新的 UnixPipes 实例\n     * @param Process         $process\n     * @param string|resource $input\n     * @return self\n     */\n    public static function create(Process $process, $input)\n    {\n        return new static($process->isTty(), $process->isPty(), $input, $process->isOutputDisabled());\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/process/pipes/Windows.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yunwuxin <448901948@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\process\\pipes;\n\nuse think\\Process;\n\nclass Windows extends Pipes\n{\n\n    /** @var array */\n    private $files = [];\n    /** @var array */\n    private $fileHandles = [];\n    /** @var array */\n    private $readBytes = [\n        Process::STDOUT => 0,\n        Process::STDERR => 0,\n    ];\n    /** @var bool */\n    private $disableOutput;\n\n    public function __construct($disableOutput, $input)\n    {\n        $this->disableOutput = (bool) $disableOutput;\n\n        if (!$this->disableOutput) {\n\n            $this->files = [\n                Process::STDOUT => tempnam(sys_get_temp_dir(), 'sf_proc_stdout'),\n                Process::STDERR => tempnam(sys_get_temp_dir(), 'sf_proc_stderr'),\n            ];\n            foreach ($this->files as $offset => $file) {\n                $this->fileHandles[$offset] = fopen($this->files[$offset], 'rb');\n                if (false === $this->fileHandles[$offset]) {\n                    throw new \\RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable');\n                }\n            }\n        }\n\n        if (is_resource($input)) {\n            $this->input = $input;\n        } else {\n            $this->inputBuffer = $input;\n        }\n    }\n\n    public function __destruct()\n    {\n        $this->close();\n        $this->removeFiles();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getDescriptors()\n    {\n        if ($this->disableOutput) {\n            $nullstream = fopen('NUL', 'c');\n\n            return [\n                ['pipe', 'r'],\n                $nullstream,\n                $nullstream,\n            ];\n        }\n\n        return [\n            ['pipe', 'r'],\n            ['file', 'NUL', 'w'],\n            ['file', 'NUL', 'w'],\n        ];\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getFiles()\n    {\n        return $this->files;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function readAndWrite($blocking, $close = false)\n    {\n        $this->write($blocking, $close);\n\n        $read = [];\n        $fh   = $this->fileHandles;\n        foreach ($fh as $type => $fileHandle) {\n            if (0 !== fseek($fileHandle, $this->readBytes[$type])) {\n                continue;\n            }\n            $data     = '';\n            $dataread = null;\n            while (!feof($fileHandle)) {\n                if (false !== $dataread = fread($fileHandle, self::CHUNK_SIZE)) {\n                    $data .= $dataread;\n                }\n            }\n            if (0 < $length = strlen($data)) {\n                $this->readBytes[$type] += $length;\n                $read[$type] = $data;\n            }\n\n            if (false === $dataread || (true === $close && feof($fileHandle) && '' === $data)) {\n                fclose($this->fileHandles[$type]);\n                unset($this->fileHandles[$type]);\n            }\n        }\n\n        return $read;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function areOpen()\n    {\n        return (bool) $this->pipes && (bool) $this->fileHandles;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function close()\n    {\n        parent::close();\n        foreach ($this->fileHandles as $handle) {\n            fclose($handle);\n        }\n        $this->fileHandles = [];\n    }\n\n    /**\n     * 创建一个新的 WindowsPipes 实例。\n     * @param Process $process\n     * @param         $input\n     * @return self\n     */\n    public static function create(Process $process, $input)\n    {\n        return new static($process->isOutputDisabled(), $input);\n    }\n\n    /**\n     * 删除临时文件\n     */\n    private function removeFiles()\n    {\n        foreach ($this->files as $filename) {\n            if (file_exists($filename)) {\n                @unlink($filename);\n            }\n        }\n        $this->files = [];\n    }\n\n    /**\n     * 写入到 stdin 输入\n     * @param bool $blocking\n     * @param bool $close\n     */\n    private function write($blocking, $close)\n    {\n        if (empty($this->pipes)) {\n            return;\n        }\n\n        $this->unblock();\n\n        $r = null !== $this->input ? ['input' => $this->input] : null;\n        $w = isset($this->pipes[0]) ? [$this->pipes[0]] : null;\n        $e = null;\n\n        if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {\n            if (!$this->hasSystemCallBeenInterrupted()) {\n                $this->pipes = [];\n            }\n\n            return;\n        }\n\n        if (0 === $n) {\n            return;\n        }\n\n        if (null !== $w && 0 < count($r)) {\n            $data = '';\n            while ($dataread = fread($r['input'], self::CHUNK_SIZE)) {\n                $data .= $dataread;\n            }\n\n            $this->inputBuffer .= $data;\n\n            if (false === $data || (true === $close && feof($r['input']) && '' === $data)) {\n                $this->input = null;\n            }\n        }\n\n        if (null !== $w && 0 < count($w)) {\n            while (strlen($this->inputBuffer)) {\n                $written = fwrite($w[0], $this->inputBuffer, 2 << 18);\n                if ($written > 0) {\n                    $this->inputBuffer = (string) substr($this->inputBuffer, $written);\n                } else {\n                    break;\n                }\n            }\n        }\n\n        if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) {\n            fclose($this->pipes[0]);\n            unset($this->pipes[0]);\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/response/Json.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\response;\n\nuse think\\Response;\n\nclass Json extends Response\n{\n    // 输出参数\n    protected $options = [\n        'json_encode_param' => JSON_UNESCAPED_UNICODE,\n    ];\n\n    protected $contentType = 'application/json';\n\n    /**\n     * 处理数据\n     * @access protected\n     * @param mixed $data 要处理的数据\n     * @return mixed\n     * @throws \\Exception\n     */\n    protected function output($data)\n    {\n        try {\n            // 返回JSON数据格式到客户端 包含状态信息\n            $data = json_encode($data, $this->options['json_encode_param']);\n\n            if ($data === false) {\n                throw new \\InvalidArgumentException(json_last_error_msg());\n            }\n\n            return $data;\n        } catch (\\Exception $e) {\n            if ($e->getPrevious()) {\n                throw $e->getPrevious();\n            }\n            throw $e;\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/response/Jsonp.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\response;\n\nuse think\\Request;\nuse think\\Response;\n\nclass Jsonp extends Response\n{\n    // 输出参数\n    protected $options = [\n        'var_jsonp_handler'     => 'callback',\n        'default_jsonp_handler' => 'jsonpReturn',\n        'json_encode_param'     => JSON_UNESCAPED_UNICODE,\n    ];\n\n    protected $contentType = 'application/javascript';\n\n    /**\n     * 处理数据\n     * @access protected\n     * @param mixed $data 要处理的数据\n     * @return mixed\n     * @throws \\Exception\n     */\n    protected function output($data)\n    {\n        try {\n            // 返回JSON数据格式到客户端 包含状态信息 [当url_common_param为false时是无法获取到$_GET的数据的，故使用Request来获取<xiaobo.sun@qq.com>]\n            $var_jsonp_handler = Request::instance()->param($this->options['var_jsonp_handler'], \"\");\n            $handler           = !empty($var_jsonp_handler) ? $var_jsonp_handler : $this->options['default_jsonp_handler'];\n\n            $data = json_encode($data, $this->options['json_encode_param']);\n\n            if ($data === false) {\n                throw new \\InvalidArgumentException(json_last_error_msg());\n            }\n\n            $data = $handler . '(' . $data . ');';\n            return $data;\n        } catch (\\Exception $e) {\n            if ($e->getPrevious()) {\n                throw $e->getPrevious();\n            }\n            throw $e;\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/response/Redirect.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\response;\n\nuse think\\Request;\nuse think\\Response;\nuse think\\Session;\nuse think\\Url;\n\nclass Redirect extends Response\n{\n\n    protected $options = [];\n\n    // URL参数\n    protected $params = [];\n\n    public function __construct($data = '', $code = 302, array $header = [], array $options = [])\n    {\n        parent::__construct($data, $code, $header, $options);\n        $this->cacheControl('no-cache,must-revalidate');\n    }\n\n    /**\n     * 处理数据\n     * @access protected\n     * @param mixed $data 要处理的数据\n     * @return mixed\n     */\n    protected function output($data)\n    {\n        $this->header['Location'] = $this->getTargetUrl();\n        return;\n    }\n\n    /**\n     * 重定向传值（通过Session）\n     * @access protected\n     * @param string|array  $name 变量名或者数组\n     * @param mixed         $value 值\n     * @return $this\n     */\n    public function with($name, $value = null)\n    {\n        if (is_array($name)) {\n            foreach ($name as $key => $val) {\n                Session::flash($key, $val);\n            }\n        } else {\n            Session::flash($name, $value);\n        }\n        return $this;\n    }\n\n    /**\n     * 获取跳转地址\n     * @return string\n     */\n    public function getTargetUrl()\n    {\n        return strpos($this->data, '://') ? $this->data : Url::build($this->data, $this->params);\n    }\n\n    public function params($params = [])\n    {\n        $this->params = $params;\n        return $this;\n    }\n\n    /**\n     * 记住当前url后跳转\n     * @return $this\n     */\n    public function remember()\n    {\n        Session::set('redirect_url', Request::instance()->url());\n        return $this;\n    }\n\n    /**\n     * 跳转到上次记住的url\n     * @return $this\n     */\n    public function restore()\n    {\n        if (Session::has('redirect_url')) {\n            $this->data = Session::get('redirect_url');\n            Session::delete('redirect_url');\n        }\n        return $this;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/response/View.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\response;\n\nuse think\\Config;\nuse think\\Response;\nuse think\\View as ViewTemplate;\n\nclass View extends Response\n{\n    // 输出参数\n    protected $options     = [];\n    protected $vars        = [];\n    protected $replace     = [];\n    protected $contentType = 'text/html';\n\n    /**\n     * 处理数据\n     * @access protected\n     * @param mixed $data 要处理的数据\n     * @return mixed\n     */\n    protected function output($data)\n    {\n        // 渲染模板输出\n        return ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str'))\n            ->fetch($data, $this->vars, $this->replace);\n    }\n\n    /**\n     * 获取视图变量\n     * @access public\n     * @param string $name 模板变量\n     * @return mixed\n     */\n    public function getVars($name = null)\n    {\n        if (is_null($name)) {\n            return $this->vars;\n        } else {\n            return isset($this->vars[$name]) ? $this->vars[$name] : null;\n        }\n    }\n\n    /**\n     * 模板变量赋值\n     * @access public\n     * @param mixed $name  变量名\n     * @param mixed $value 变量值\n     * @return $this\n     */\n    public function assign($name, $value = '')\n    {\n        if (is_array($name)) {\n            $this->vars = array_merge($this->vars, $name);\n            return $this;\n        } else {\n            $this->vars[$name] = $value;\n        }\n        return $this;\n    }\n\n    /**\n     * 视图内容替换\n     * @access public\n     * @param string|array $content 被替换内容（支持批量替换）\n     * @param string  $replace    替换内容\n     * @return $this\n     */\n    public function replace($content, $replace = '')\n    {\n        if (is_array($content)) {\n            $this->replace = array_merge($this->replace, $content);\n        } else {\n            $this->replace[$content] = $replace;\n        }\n        return $this;\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/response/Xml.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\response;\n\nuse think\\Response;\n\nclass Xml extends Response\n{\n    // 输出参数\n    protected $options = [\n        // 根节点名\n        'root_node' => 'think',\n        // 根节点属性\n        'root_attr' => '',\n        //数字索引的子节点名\n        'item_node' => 'item',\n        // 数字索引子节点key转换的属性名\n        'item_key'  => 'id',\n        // 数据编码\n        'encoding'  => 'utf-8',\n    ];\n\n    protected $contentType = 'text/xml';\n\n    /**\n     * 处理数据\n     * @access protected\n     * @param mixed $data 要处理的数据\n     * @return mixed\n     */\n    protected function output($data)\n    {\n        // XML数据转换\n        return $this->xmlEncode($data, $this->options['root_node'], $this->options['item_node'], $this->options['root_attr'], $this->options['item_key'], $this->options['encoding']);\n    }\n\n    /**\n     * XML编码\n     * @param mixed $data 数据\n     * @param string $root 根节点名\n     * @param string $item 数字索引的子节点名\n     * @param string $attr 根节点属性\n     * @param string $id   数字索引子节点key转换的属性名\n     * @param string $encoding 数据编码\n     * @return string\n     */\n    protected function xmlEncode($data, $root, $item, $attr, $id, $encoding)\n    {\n        if (is_array($attr)) {\n            $array = [];\n            foreach ($attr as $key => $value) {\n                $array[] = \"{$key}=\\\"{$value}\\\"\";\n            }\n            $attr = implode(' ', $array);\n        }\n        $attr = trim($attr);\n        $attr = empty($attr) ? '' : \" {$attr}\";\n        $xml  = \"<?xml version=\\\"1.0\\\" encoding=\\\"{$encoding}\\\"?>\";\n        $xml .= \"<{$root}{$attr}>\";\n        $xml .= $this->dataToXml($data, $item, $id);\n        $xml .= \"</{$root}>\";\n        return $xml;\n    }\n\n    /**\n     * 数据XML编码\n     * @param mixed  $data 数据\n     * @param string $item 数字索引时的节点名称\n     * @param string $id   数字索引key转换为的属性名\n     * @return string\n     */\n    protected function dataToXml($data, $item, $id)\n    {\n        $xml = $attr = '';\n        foreach ($data as $key => $val) {\n            if (is_numeric($key)) {\n                $id && $attr = \" {$id}=\\\"{$key}\\\"\";\n                $key         = $item;\n            }\n            $xml .= \"<{$key}{$attr}>\";\n            $xml .= (is_array($val) || is_object($val)) ? $this->dataToXml($val, $item, $id) : $val;\n            $xml .= \"</{$key}>\";\n        }\n        return $xml;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/session/driver/Memcache.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\session\\driver;\n\nuse SessionHandler;\nuse think\\Exception;\n\nclass Memcache extends SessionHandler\n{\n    protected $handler = null;\n    protected $config  = [\n        'host'         => '127.0.0.1', // memcache主机\n        'port'         => 11211, // memcache端口\n        'expire'       => 3600, // session有效期\n        'timeout'      => 0, // 连接超时时间（单位：毫秒）\n        'persistent'   => true, // 长连接\n        'session_name' => '', // memcache key前缀\n    ];\n\n    public function __construct($config = [])\n    {\n        $this->config = array_merge($this->config, $config);\n    }\n\n    /**\n     * 打开Session\n     * @access public\n     * @param string    $savePath\n     * @param mixed     $sessName\n     */\n    public function open($savePath, $sessName)\n    {\n        // 检测php环境\n        if (!extension_loaded('memcache')) {\n            throw new Exception('not support:memcache');\n        }\n        $this->handler = new \\Memcache;\n        // 支持集群\n        $hosts = explode(',', $this->config['host']);\n        $ports = explode(',', $this->config['port']);\n        if (empty($ports[0])) {\n            $ports[0] = 11211;\n        }\n        // 建立连接\n        foreach ((array) $hosts as $i => $host) {\n            $port = isset($ports[$i]) ? $ports[$i] : $ports[0];\n            $this->config['timeout'] > 0 ?\n            $this->handler->addServer($host, $port, $this->config['persistent'], 1, $this->config['timeout']) :\n            $this->handler->addServer($host, $port, $this->config['persistent'], 1);\n        }\n        return true;\n    }\n\n    /**\n     * 关闭Session\n     * @access public\n     */\n    public function close()\n    {\n        $this->gc(ini_get('session.gc_maxlifetime'));\n        $this->handler->close();\n        $this->handler = null;\n        return true;\n    }\n\n    /**\n     * 读取Session\n     * @access public\n     * @param string $sessID\n     */\n    public function read($sessID)\n    {\n        return (string) $this->handler->get($this->config['session_name'] . $sessID);\n    }\n\n    /**\n     * 写入Session\n     * @access public\n     * @param string    $sessID\n     * @param String    $sessData\n     * @return bool\n     */\n    public function write($sessID, $sessData)\n    {\n        return $this->handler->set($this->config['session_name'] . $sessID, $sessData, 0, $this->config['expire']);\n    }\n\n    /**\n     * 删除Session\n     * @access public\n     * @param string $sessID\n     * @return bool\n     */\n    public function destroy($sessID)\n    {\n        return $this->handler->delete($this->config['session_name'] . $sessID);\n    }\n\n    /**\n     * Session 垃圾回收\n     * @access public\n     * @param string $sessMaxLifeTime\n     * @return true\n     */\n    public function gc($sessMaxLifeTime)\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/session/driver/Memcached.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\session\\driver;\n\nuse SessionHandler;\nuse think\\Exception;\n\nclass Memcached extends SessionHandler\n{\n    protected $handler = null;\n    protected $config  = [\n        'host'         => '127.0.0.1', // memcache主机\n        'port'         => 11211, // memcache端口\n        'expire'       => 3600, // session有效期\n        'timeout'      => 0, // 连接超时时间（单位：毫秒）\n        'session_name' => '', // memcache key前缀\n        'username'     => '', //账号\n        'password'     => '', //密码\n    ];\n\n    public function __construct($config = [])\n    {\n        $this->config = array_merge($this->config, $config);\n    }\n\n    /**\n     * 打开Session\n     * @access public\n     * @param string    $savePath\n     * @param mixed     $sessName\n     */\n    public function open($savePath, $sessName)\n    {\n        // 检测php环境\n        if (!extension_loaded('memcached')) {\n            throw new Exception('not support:memcached');\n        }\n        $this->handler = new \\Memcached;\n        // 设置连接超时时间（单位：毫秒）\n        if ($this->config['timeout'] > 0) {\n            $this->handler->setOption(\\Memcached::OPT_CONNECT_TIMEOUT, $this->config['timeout']);\n        }\n        // 支持集群\n        $hosts = explode(',', $this->config['host']);\n        $ports = explode(',', $this->config['port']);\n        if (empty($ports[0])) {\n            $ports[0] = 11211;\n        }\n        // 建立连接\n        $servers = [];\n        foreach ((array) $hosts as $i => $host) {\n            $servers[] = [$host, (isset($ports[$i]) ? $ports[$i] : $ports[0]), 1];\n        }\n        $this->handler->addServers($servers);\n        if ('' != $this->config['username']) {\n            $this->handler->setOption(\\Memcached::OPT_BINARY_PROTOCOL, true);\n            $this->handler->setSaslAuthData($this->config['username'], $this->config['password']);\n        }\n        return true;\n    }\n\n    /**\n     * 关闭Session\n     * @access public\n     */\n    public function close()\n    {\n        $this->gc(ini_get('session.gc_maxlifetime'));\n        $this->handler->quit();\n        $this->handler = null;\n        return true;\n    }\n\n    /**\n     * 读取Session\n     * @access public\n     * @param string $sessID\n     */\n    public function read($sessID)\n    {\n        return (string) $this->handler->get($this->config['session_name'] . $sessID);\n    }\n\n    /**\n     * 写入Session\n     * @access public\n     * @param string $sessID\n     * @param String $sessData\n     * @return bool\n     */\n    public function write($sessID, $sessData)\n    {\n        return $this->handler->set($this->config['session_name'] . $sessID, $sessData, $this->config['expire']);\n    }\n\n    /**\n     * 删除Session\n     * @access public\n     * @param string $sessID\n     * @return bool\n     */\n    public function destroy($sessID)\n    {\n        return $this->handler->delete($this->config['session_name'] . $sessID);\n    }\n\n    /**\n     * Session 垃圾回收\n     * @access public\n     * @param string $sessMaxLifeTime\n     * @return true\n     */\n    public function gc($sessMaxLifeTime)\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/session/driver/Redis.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\session\\driver;\n\nuse SessionHandler;\nuse think\\Exception;\n\nclass Redis extends SessionHandler\n{\n    /** @var \\Redis */\n    protected $handler = null;\n    protected $config  = [\n        'host'         => '127.0.0.1', // redis主机\n        'port'         => 6379, // redis端口\n        'password'     => '', // 密码\n        'select'       => 0, // 操作库\n        'expire'       => 3600, // 有效期(秒)\n        'timeout'      => 0, // 超时时间(秒)\n        'persistent'   => true, // 是否长连接\n        'session_name' => '', // sessionkey前缀\n    ];\n\n    public function __construct($config = [])\n    {\n        $this->config = array_merge($this->config, $config);\n    }\n\n    /**\n     * 打开Session\n     * @access public\n     * @param string $savePath\n     * @param mixed  $sessName\n     * @return bool\n     * @throws Exception\n     */\n    public function open($savePath, $sessName)\n    {\n        // 检测php环境\n        if (!extension_loaded('redis')) {\n            throw new Exception('not support:redis');\n        }\n        $this->handler = new \\Redis;\n\n        // 建立连接\n        $func = $this->config['persistent'] ? 'pconnect' : 'connect';\n        $this->handler->$func($this->config['host'], $this->config['port'], $this->config['timeout']);\n\n        if ('' != $this->config['password']) {\n            $this->handler->auth($this->config['password']);\n        }\n\n        if (0 != $this->config['select']) {\n            $this->handler->select($this->config['select']);\n        }\n\n        return true;\n    }\n\n    /**\n     * 关闭Session\n     * @access public\n     */\n    public function close()\n    {\n        $this->gc(ini_get('session.gc_maxlifetime'));\n        $this->handler->close();\n        $this->handler = null;\n        return true;\n    }\n\n    /**\n     * 读取Session\n     * @access public\n     * @param string $sessID\n     * @return string\n     */\n    public function read($sessID)\n    {\n        return (string) $this->handler->get($this->config['session_name'] . $sessID);\n    }\n\n    /**\n     * 写入Session\n     * @access public\n     * @param string $sessID\n     * @param String $sessData\n     * @return bool\n     */\n    public function write($sessID, $sessData)\n    {\n        if ($this->config['expire'] > 0) {\n            return $this->handler->setex($this->config['session_name'] . $sessID, $this->config['expire'], $sessData);\n        } else {\n            return $this->handler->set($this->config['session_name'] . $sessID, $sessData);\n        }\n    }\n\n    /**\n     * 删除Session\n     * @access public\n     * @param string $sessID\n     * @return bool\n     */\n    public function destroy($sessID)\n    {\n        return $this->handler->delete($this->config['session_name'] . $sessID) > 0;\n    }\n\n    /**\n     * Session 垃圾回收\n     * @access public\n     * @param string $sessMaxLifeTime\n     * @return bool\n     */\n    public function gc($sessMaxLifeTime)\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/template/TagLib.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\template;\n\nuse think\\Exception;\n\n/**\n * ThinkPHP标签库TagLib解析基类\n * @category   Think\n * @package  Think\n * @subpackage  Template\n * @author    liu21st <liu21st@gmail.com>\n */\nclass TagLib\n{\n\n    /**\n     * 标签库定义XML文件\n     * @var string\n     * @access protected\n     */\n    protected $xml  = '';\n    protected $tags = []; // 标签定义\n    /**\n     * 标签库名称\n     * @var string\n     * @access protected\n     */\n    protected $tagLib = '';\n\n    /**\n     * 标签库标签列表\n     * @var array\n     * @access protected\n     */\n    protected $tagList = [];\n\n    /**\n     * 标签库分析数组\n     * @var array\n     * @access protected\n     */\n    protected $parse = [];\n\n    /**\n     * 标签库是否有效\n     * @var bool\n     * @access protected\n     */\n    protected $valid = false;\n\n    /**\n     * 当前模板对象\n     * @var object\n     * @access protected\n     */\n    protected $tpl;\n\n    protected $comparison = [' nheq ' => ' !== ', ' heq ' => ' === ', ' neq ' => ' != ', ' eq ' => ' == ', ' egt ' => ' >= ', ' gt ' => ' > ', ' elt ' => ' <= ', ' lt ' => ' < '];\n\n    /**\n     * 构造函数\n     * @access public\n     * @param \\stdClass $template 模板引擎对象\n     */\n    public function __construct($template)\n    {\n        $this->tpl = $template;\n    }\n\n    /**\n     * 按签标库替换页面中的标签\n     * @access public\n     * @param  string $content 模板内容\n     * @param  string $lib 标签库名\n     * @return void\n     */\n    public function parseTag(&$content, $lib = '')\n    {\n        $tags = [];\n        $lib  = $lib ? strtolower($lib) . ':' : '';\n        foreach ($this->tags as $name => $val) {\n            $close                      = !isset($val['close']) || $val['close'] ? 1 : 0;\n            $tags[$close][$lib . $name] = $name;\n            if (isset($val['alias'])) {\n                // 别名设置\n                $array = (array) $val['alias'];\n                foreach (explode(',', $array[0]) as $v) {\n                    $tags[$close][$lib . $v] = $name;\n                }\n            }\n        }\n\n        // 闭合标签\n        if (!empty($tags[1])) {\n            $nodes = [];\n            $regex = $this->getRegex(array_keys($tags[1]), 1);\n            if (preg_match_all($regex, $content, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {\n                $right = [];\n                foreach ($matches as $match) {\n                    if ('' == $match[1][0]) {\n                        $name = strtolower($match[2][0]);\n                        // 如果有没闭合的标签头则取出最后一个\n                        if (!empty($right[$name])) {\n                            // $match[0][1]为标签结束符在模板中的位置\n                            $nodes[$match[0][1]] = [\n                                'name'  => $name,\n                                'begin' => array_pop($right[$name]), // 标签开始符\n                                'end'   => $match[0], // 标签结束符\n                            ];\n                        }\n                    } else {\n                        // 标签头压入栈\n                        $right[strtolower($match[1][0])][] = $match[0];\n                    }\n                }\n                unset($right, $matches);\n                // 按标签在模板中的位置从后向前排序\n                krsort($nodes);\n            }\n\n            $break = '<!--###break###--!>';\n            if ($nodes) {\n                $beginArray = [];\n                // 标签替换 从后向前\n                foreach ($nodes as $pos => $node) {\n                    // 对应的标签名\n                    $name  = $tags[1][$node['name']];\n                    $alias = $lib . $name != $node['name'] ? ($lib ? strstr($node['name'], $lib) : $node['name']) : '';\n                    // 解析标签属性\n                    $attrs  = $this->parseAttr($node['begin'][0], $name, $alias);\n                    $method = 'tag' . $name;\n                    // 读取标签库中对应的标签内容 replace[0]用来替换标签头，replace[1]用来替换标签尾\n                    $replace = explode($break, $this->$method($attrs, $break));\n                    if (count($replace) > 1) {\n                        while ($beginArray) {\n                            $begin = end($beginArray);\n                            // 判断当前标签尾的位置是否在栈中最后一个标签头的后面，是则为子标签\n                            if ($node['end'][1] > $begin['pos']) {\n                                break;\n                            } else {\n                                // 不为子标签时，取出栈中最后一个标签头\n                                $begin = array_pop($beginArray);\n                                // 替换标签头部\n                                $content = substr_replace($content, $begin['str'], $begin['pos'], $begin['len']);\n                            }\n                        }\n                        // 替换标签尾部\n                        $content = substr_replace($content, $replace[1], $node['end'][1], strlen($node['end'][0]));\n                        // 把标签头压入栈\n                        $beginArray[] = ['pos' => $node['begin'][1], 'len' => strlen($node['begin'][0]), 'str' => $replace[0]];\n                    }\n                }\n                while ($beginArray) {\n                    $begin = array_pop($beginArray);\n                    // 替换标签头部\n                    $content = substr_replace($content, $begin['str'], $begin['pos'], $begin['len']);\n                }\n            }\n        }\n        // 自闭合标签\n        if (!empty($tags[0])) {\n            $regex   = $this->getRegex(array_keys($tags[0]), 0);\n            $content = preg_replace_callback($regex, function ($matches) use (&$tags, &$lib) {\n                // 对应的标签名\n                $name  = $tags[0][strtolower($matches[1])];\n                $alias = $lib . $name != $matches[1] ? ($lib ? strstr($matches[1], $lib) : $matches[1]) : '';\n                // 解析标签属性\n                $attrs  = $this->parseAttr($matches[0], $name, $alias);\n                $method = 'tag' . $name;\n                return $this->$method($attrs, '');\n            }, $content);\n        }\n        return;\n    }\n\n    /**\n     * 按标签生成正则\n     * @access private\n     * @param  array|string     $tags 标签名\n     * @param  boolean          $close 是否为闭合标签\n     * @return string\n     */\n    public function getRegex($tags, $close)\n    {\n        $begin   = $this->tpl->config('taglib_begin');\n        $end     = $this->tpl->config('taglib_end');\n        $single  = strlen(ltrim($begin, '\\\\')) == 1 && strlen(ltrim($end, '\\\\')) == 1 ? true : false;\n        $tagName = is_array($tags) ? implode('|', $tags) : $tags;\n        if ($single) {\n            if ($close) {\n                // 如果是闭合标签\n                $regex = $begin . '(?:(' . $tagName . ')\\b(?>[^' . $end . ']*)|\\/(' . $tagName . '))' . $end;\n            } else {\n                $regex = $begin . '(' . $tagName . ')\\b(?>[^' . $end . ']*)' . $end;\n            }\n        } else {\n            if ($close) {\n                // 如果是闭合标签\n                $regex = $begin . '(?:(' . $tagName . ')\\b(?>(?:(?!' . $end . ').)*)|\\/(' . $tagName . '))' . $end;\n            } else {\n                $regex = $begin . '(' . $tagName . ')\\b(?>(?:(?!' . $end . ').)*)' . $end;\n            }\n        }\n        return '/' . $regex . '/is';\n    }\n\n    /**\n     * 分析标签属性 正则方式\n     * @access public\n     * @param string $str 标签属性字符串\n     * @param string $name 标签名\n     * @param string $alias 别名\n     * @return array\n     */\n    public function parseAttr($str, $name, $alias = '')\n    {\n        $regex  = '/\\s+(?>(?P<name>[\\w-]+)\\s*)=(?>\\s*)([\\\"\\'])(?P<value>(?:(?!\\\\2).)*)\\\\2/is';\n        $result = [];\n        if (preg_match_all($regex, $str, $matches)) {\n            foreach ($matches['name'] as $key => $val) {\n                $result[$val] = $matches['value'][$key];\n            }\n            if (!isset($this->tags[$name])) {\n                // 检测是否存在别名定义\n                foreach ($this->tags as $key => $val) {\n                    if (isset($val['alias'])) {\n                        $array = (array) $val['alias'];\n                        if (in_array($name, explode(',', $array[0]))) {\n                            $tag           = $val;\n                            $type          = !empty($array[1]) ? $array[1] : 'type';\n                            $result[$type] = $name;\n                            break;\n                        }\n                    }\n                }\n            } else {\n                $tag = $this->tags[$name];\n                // 设置了标签别名\n                if (!empty($alias) && isset($tag['alias'])) {\n                    $type          = !empty($tag['alias'][1]) ? $tag['alias'][1] : 'type';\n                    $result[$type] = $alias;\n                }\n            }\n            if (!empty($tag['must'])) {\n                $must = explode(',', $tag['must']);\n                foreach ($must as $name) {\n                    if (!isset($result[$name])) {\n                        throw new Exception('tag attr must:' . $name);\n                    }\n                }\n            }\n        } else {\n            // 允许直接使用表达式的标签\n            if (!empty($this->tags[$name]['expression'])) {\n                static $_taglibs;\n                if (!isset($_taglibs[$name])) {\n                    $_taglibs[$name][0] = strlen(ltrim($this->tpl->config('taglib_begin'), '\\\\') . $name);\n                    $_taglibs[$name][1] = strlen(ltrim($this->tpl->config('taglib_end'), '\\\\'));\n                }\n                $result['expression'] = substr($str, $_taglibs[$name][0], -$_taglibs[$name][1]);\n                // 清除自闭合标签尾部/\n                $result['expression'] = rtrim($result['expression'], '/');\n                $result['expression'] = trim($result['expression']);\n            } elseif (empty($this->tags[$name]) || !empty($this->tags[$name]['attr'])) {\n                throw new Exception('tag error:' . $name);\n            }\n        }\n        return $result;\n    }\n\n    /**\n     * 解析条件表达式\n     * @access public\n     * @param  string $condition 表达式标签内容\n     * @return string\n     */\n    public function parseCondition($condition)\n    {\n        if (strpos($condition, ':')) {\n            $condition = ' ' . substr(strstr($condition, ':'), 1);\n        }\n        $condition = str_ireplace(array_keys($this->comparison), array_values($this->comparison), $condition);\n        $this->tpl->parseVar($condition);\n        // $this->tpl->parseVarFunction($condition); // XXX: 此句能解析表达式中用|分隔的函数，但表达式中如果有|、||这样的逻辑运算就产生了歧异\n        return $condition;\n    }\n\n    /**\n     * 自动识别构建变量\n     * @access public\n     * @param string $name 变量描述\n     * @return string\n     */\n    public function autoBuildVar(&$name)\n    {\n        $flag = substr($name, 0, 1);\n        if (':' == $flag) {\n            // 以:开头为函数调用，解析前去掉:\n            $name = substr($name, 1);\n        } elseif ('$' != $flag && preg_match('/[a-zA-Z_]/', $flag)) {\n            // XXX: 这句的写法可能还需要改进\n            // 常量不需要解析\n            if (defined($name)) {\n                return $name;\n            }\n            // 不以$开头并且也不是常量，自动补上$前缀\n            $name = '$' . $name;\n        }\n        $this->tpl->parseVar($name);\n        $this->tpl->parseVarFunction($name);\n        return $name;\n    }\n\n    /**\n     * 获取标签列表\n     * @access public\n     * @return array\n     */\n    // 获取标签定义\n    public function getTags()\n    {\n        return $this->tags;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/template/driver/File.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\template\\driver;\n\nuse think\\Exception;\n\nclass File\n{\n    /**\n     * 写入编译缓存\n     * @param string $cacheFile 缓存的文件名\n     * @param string $content 缓存的内容\n     * @return void|array\n     */\n    public function write($cacheFile, $content)\n    {\n        // 检测模板目录\n        $dir = dirname($cacheFile);\n        if (!is_dir($dir)) {\n            mkdir($dir, 0755, true);\n        }\n        // 生成模板缓存文件\n        if (false === file_put_contents($cacheFile, $content)) {\n            throw new Exception('cache write error:' . $cacheFile, 11602);\n        }\n    }\n\n    /**\n     * 读取编译编译\n     * @param string  $cacheFile 缓存的文件名\n     * @param array   $vars 变量数组\n     * @return void\n     */\n    public function read($cacheFile, $vars = [])\n    {\n        if (!empty($vars) && is_array($vars)) {\n            // 模板阵列变量分解成为独立变量\n            extract($vars, EXTR_OVERWRITE);\n        }\n        //载入模版缓存文件\n        include $cacheFile;\n    }\n\n    /**\n     * 检查编译缓存是否有效\n     * @param string  $cacheFile 缓存的文件名\n     * @param int     $cacheTime 缓存时间\n     * @return boolean\n     */\n    public function check($cacheFile, $cacheTime)\n    {\n        // 缓存文件不存在, 直接返回false\n        if (!file_exists($cacheFile)) {\n            return false;\n        }\n        if (0 != $cacheTime && $_SERVER['REQUEST_TIME'] > filemtime($cacheFile) + $cacheTime) {\n            // 缓存是否在有效期\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/template/taglib/Cx.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\template\\taglib;\n\nuse think\\template\\TagLib;\n\n/**\n * CX标签库解析类\n * @category   Think\n * @package  Think\n * @subpackage  Driver.Taglib\n * @author    liu21st <liu21st@gmail.com>\n */\nclass Cx extends Taglib\n{\n\n    // 标签定义\n    protected $tags = [\n        // 标签定义： attr 属性列表 close 是否闭合（0 或者1 默认1） alias 标签别名 level 嵌套层次\n        'php'        => ['attr' => ''],\n        'volist'     => ['attr' => 'name,id,offset,length,key,mod', 'alias' => 'iterate'],\n        'foreach'    => ['attr' => 'name,id,item,key,offset,length,mod', 'expression' => true],\n        'if'         => ['attr' => 'condition', 'expression' => true],\n        'elseif'     => ['attr' => 'condition', 'close' => 0, 'expression' => true],\n        'else'       => ['attr' => '', 'close' => 0],\n        'switch'     => ['attr' => 'name', 'expression' => true],\n        'case'       => ['attr' => 'value,break', 'expression' => true],\n        'default'    => ['attr' => '', 'close' => 0],\n        'compare'    => ['attr' => 'name,value,type', 'alias' => ['eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq', 'type']],\n        'range'      => ['attr' => 'name,value,type', 'alias' => ['in,notin,between,notbetween', 'type']],\n        'empty'      => ['attr' => 'name'],\n        'notempty'   => ['attr' => 'name'],\n        'present'    => ['attr' => 'name'],\n        'notpresent' => ['attr' => 'name'],\n        'defined'    => ['attr' => 'name'],\n        'notdefined' => ['attr' => 'name'],\n        'load'       => ['attr' => 'file,href,type,value,basepath', 'close' => 0, 'alias' => ['import,css,js', 'type']],\n        'assign'     => ['attr' => 'name,value', 'close' => 0],\n        'define'     => ['attr' => 'name,value', 'close' => 0],\n        'for'        => ['attr' => 'start,end,name,comparison,step'],\n        'url'        => ['attr' => 'link,vars,suffix,domain', 'close' => 0, 'expression' => true],\n        'function'   => ['attr' => 'name,vars,use,call'],\n    ];\n\n    /**\n     * php标签解析\n     * 格式：\n     * {php}echo $name{/php}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagPhp($tag, $content)\n    {\n        $parseStr = '<?php ' . $content . ' ?>';\n        return $parseStr;\n    }\n\n    /**\n     * volist标签解析 循环输出数据集\n     * 格式：\n     * {volist name=\"userList\" id=\"user\" empty=\"\"}\n     * {user.username}\n     * {user.email}\n     * {/volist}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string|void\n     */\n    public function tagVolist($tag, $content)\n    {\n        $name   = $tag['name'];\n        $id     = $tag['id'];\n        $empty  = isset($tag['empty']) ? $tag['empty'] : '';\n        $key    = !empty($tag['key']) ? $tag['key'] : 'i';\n        $mod    = isset($tag['mod']) ? $tag['mod'] : '2';\n        $offset = !empty($tag['offset']) && is_numeric($tag['offset']) ? intval($tag['offset']) : 0;\n        $length = !empty($tag['length']) && is_numeric($tag['length']) ? intval($tag['length']) : 'null';\n        // 允许使用函数设定数据集 <volist name=\":fun('arg')\" id=\"vo\">{$vo.name}</volist>\n        $parseStr = '<?php ';\n        $flag     = substr($name, 0, 1);\n        if (':' == $flag) {\n            $name = $this->autoBuildVar($name);\n            $parseStr .= '$_result=' . $name . ';';\n            $name = '$_result';\n        } else {\n            $name = $this->autoBuildVar($name);\n        }\n\n        $parseStr .= 'if(is_array(' . $name . ') || ' . $name . ' instanceof \\think\\Collection || ' . $name . ' instanceof \\think\\Paginator): $' . $key . ' = 0;';\n        // 设置了输出数组长度\n        if (0 != $offset || 'null' != $length) {\n            $parseStr .= '$__LIST__ = is_array(' . $name . ') ? array_slice(' . $name . ',' . $offset . ',' . $length . ', true) : ' . $name . '->slice(' . $offset . ',' . $length . ', true); ';\n        } else {\n            $parseStr .= ' $__LIST__ = ' . $name . ';';\n        }\n        $parseStr .= 'if( count($__LIST__)==0 ) : echo \"' . $empty . '\" ;';\n        $parseStr .= 'else: ';\n        $parseStr .= 'foreach($__LIST__ as $key=>$' . $id . '): ';\n        $parseStr .= '$mod = ($' . $key . ' % ' . $mod . ' );';\n        $parseStr .= '++$' . $key . ';?>';\n        $parseStr .= $content;\n        $parseStr .= '<?php endforeach; endif; else: echo \"' . $empty . '\" ;endif; ?>';\n\n        if (!empty($parseStr)) {\n            return $parseStr;\n        }\n        return;\n    }\n\n    /**\n     * foreach标签解析 循环输出数据集\n     * 格式：\n     * {foreach name=\"userList\" id=\"user\" key=\"key\" index=\"i\" mod=\"2\" offset=\"3\" length=\"5\" empty=\"\"}\n     * {user.username}\n     * {/foreach}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string|void\n     */\n    public function tagForeach($tag, $content)\n    {\n        // 直接使用表达式\n        if (!empty($tag['expression'])) {\n            $expression = ltrim(rtrim($tag['expression'], ')'), '(');\n            $expression = $this->autoBuildVar($expression);\n            $parseStr   = '<?php foreach(' . $expression . '): ?>';\n            $parseStr .= $content;\n            $parseStr .= '<?php endforeach; ?>';\n            return $parseStr;\n        }\n        $name   = $tag['name'];\n        $key    = !empty($tag['key']) ? $tag['key'] : 'key';\n        $item   = !empty($tag['id']) ? $tag['id'] : $tag['item'];\n        $empty  = isset($tag['empty']) ? $tag['empty'] : '';\n        $offset = !empty($tag['offset']) && is_numeric($tag['offset']) ? intval($tag['offset']) : 0;\n        $length = !empty($tag['length']) && is_numeric($tag['length']) ? intval($tag['length']) : 'null';\n\n        $parseStr = '<?php ';\n        // 支持用函数传数组\n        if (':' == substr($name, 0, 1)) {\n            $var  = '$_' . uniqid();\n            $name = $this->autoBuildVar($name);\n            $parseStr .= $var . '=' . $name . '; ';\n            $name = $var;\n        } else {\n            $name = $this->autoBuildVar($name);\n        }\n        $parseStr .= 'if(is_array(' . $name . ') || ' . $name . ' instanceof \\think\\Collection || ' . $name . ' instanceof \\think\\Paginator): ';\n        // 设置了输出数组长度\n        if (0 != $offset || 'null' != $length) {\n            if (!isset($var)) {\n                $var = '$_' . uniqid();\n            }\n            $parseStr .= $var . ' = is_array(' . $name . ') ? array_slice(' . $name . ',' . $offset . ',' . $length . ', true) : ' . $name . '->slice(' . $offset . ',' . $length . ', true); ';\n        } else {\n            $var = &$name;\n        }\n\n        $parseStr .= 'if( count(' . $var . ')==0 ) : echo \"' . $empty . '\" ;';\n        $parseStr .= 'else: ';\n\n        // 设置了索引项\n        if (isset($tag['index'])) {\n            $index = $tag['index'];\n            $parseStr .= '$' . $index . '=0; ';\n        }\n        $parseStr .= 'foreach(' . $var . ' as $' . $key . '=>$' . $item . '): ';\n        // 设置了索引项\n        if (isset($tag['index'])) {\n            $index = $tag['index'];\n            if (isset($tag['mod'])) {\n                $mod = (int) $tag['mod'];\n                $parseStr .= '$mod = ($' . $index . ' % ' . $mod . '); ';\n            }\n            $parseStr .= '++$' . $index . '; ';\n        }\n        $parseStr .= '?>';\n        // 循环体中的内容\n        $parseStr .= $content;\n        $parseStr .= '<?php endforeach; endif; else: echo \"' . $empty . '\" ;endif; ?>';\n\n        if (!empty($parseStr)) {\n            return $parseStr;\n        }\n        return;\n    }\n\n    /**\n     * if标签解析\n     * 格式：\n     * {if condition=\" $a eq 1\"}\n     * {elseif condition=\"$a eq 2\" /}\n     * {else /}\n     * {/if}\n     * 表达式支持 eq neq gt egt lt elt == > >= < <= or and || &&\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagIf($tag, $content)\n    {\n        $condition = !empty($tag['expression']) ? $tag['expression'] : $tag['condition'];\n        $condition = $this->parseCondition($condition);\n        $parseStr  = '<?php if(' . $condition . '): ?>' . $content . '<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * elseif标签解析\n     * 格式：见if标签\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagElseif($tag, $content)\n    {\n        $condition = !empty($tag['expression']) ? $tag['expression'] : $tag['condition'];\n        $condition = $this->parseCondition($condition);\n        $parseStr  = '<?php elseif(' . $condition . '): ?>';\n        return $parseStr;\n    }\n\n    /**\n     * else标签解析\n     * 格式：见if标签\n     * @access public\n     * @param array $tag 标签属性\n     * @return string\n     */\n    public function tagElse($tag)\n    {\n        $parseStr = '<?php else: ?>';\n        return $parseStr;\n    }\n\n    /**\n     * switch标签解析\n     * 格式：\n     * {switch name=\"a.name\"}\n     * {case value=\"1\" break=\"false\"}1{/case}\n     * {case value=\"2\" }2{/case}\n     * {default /}other\n     * {/switch}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagSwitch($tag, $content)\n    {\n        $name     = !empty($tag['expression']) ? $tag['expression'] : $tag['name'];\n        $name     = $this->autoBuildVar($name);\n        $parseStr = '<?php switch(' . $name . '): ?>' . $content . '<?php endswitch; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * case标签解析 需要配合switch才有效\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagCase($tag, $content)\n    {\n        $value = !empty($tag['expression']) ? $tag['expression'] : $tag['value'];\n        $flag  = substr($value, 0, 1);\n        if ('$' == $flag || ':' == $flag) {\n            $value = $this->autoBuildVar($value);\n            $value = 'case ' . $value . ':';\n        } elseif (strpos($value, '|')) {\n            $values = explode('|', $value);\n            $value  = '';\n            foreach ($values as $val) {\n                $value .= 'case \"' . addslashes($val) . '\":';\n            }\n        } else {\n            $value = 'case \"' . $value . '\":';\n        }\n        $parseStr = '<?php ' . $value . ' ?>' . $content;\n        $isBreak  = isset($tag['break']) ? $tag['break'] : '';\n        if ('' == $isBreak || $isBreak) {\n            $parseStr .= '<?php break; ?>';\n        }\n        return $parseStr;\n    }\n\n    /**\n     * default标签解析 需要配合switch才有效\n     * 使用： {default /}ddfdf\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagDefault($tag)\n    {\n        $parseStr = '<?php default: ?>';\n        return $parseStr;\n    }\n\n    /**\n     * compare标签解析\n     * 用于值的比较 支持 eq neq gt lt egt elt heq nheq 默认是eq\n     * 格式： {compare name=\"\" type=\"eq\" value=\"\" }content{/compare}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagCompare($tag, $content)\n    {\n        $name  = $tag['name'];\n        $value = $tag['value'];\n        $type  = isset($tag['type']) ? $tag['type'] : 'eq'; // 比较类型\n        $name  = $this->autoBuildVar($name);\n        $flag  = substr($value, 0, 1);\n        if ('$' == $flag || ':' == $flag) {\n            $value = $this->autoBuildVar($value);\n        } else {\n            $value = '\\'' . $value . '\\'';\n        }\n        switch ($type) {\n            case 'equal':\n                $type = 'eq';\n                break;\n            case 'notequal':\n                $type = 'neq';\n                break;\n        }\n        $type     = $this->parseCondition(' ' . $type . ' ');\n        $parseStr = '<?php if(' . $name . ' ' . $type . ' ' . $value . '): ?>' . $content . '<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * range标签解析\n     * 如果某个变量存在于某个范围 则输出内容 type= in 表示在范围内 否则表示在范围外\n     * 格式： {range name=\"var|function\"  value=\"val\" type='in|notin' }content{/range}\n     * example: {range name=\"a\"  value=\"1,2,3\" type='in' }content{/range}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagRange($tag, $content)\n    {\n        $name  = $tag['name'];\n        $value = $tag['value'];\n        $type  = isset($tag['type']) ? $tag['type'] : 'in'; // 比较类型\n\n        $name = $this->autoBuildVar($name);\n        $flag = substr($value, 0, 1);\n        if ('$' == $flag || ':' == $flag) {\n            $value = $this->autoBuildVar($value);\n            $str   = 'is_array(' . $value . ')?' . $value . ':explode(\\',\\',' . $value . ')';\n        } else {\n            $value = '\"' . $value . '\"';\n            $str   = 'explode(\\',\\',' . $value . ')';\n        }\n        if ('between' == $type) {\n            $parseStr = '<?php $_RANGE_VAR_=' . $str . ';if(' . $name . '>= $_RANGE_VAR_[0] && ' . $name . '<= $_RANGE_VAR_[1]):?>' . $content . '<?php endif; ?>';\n        } elseif ('notbetween' == $type) {\n            $parseStr = '<?php $_RANGE_VAR_=' . $str . ';if(' . $name . '<$_RANGE_VAR_[0] || ' . $name . '>$_RANGE_VAR_[1]):?>' . $content . '<?php endif; ?>';\n        } else {\n            $fun      = ('in' == $type) ? 'in_array' : '!in_array';\n            $parseStr = '<?php if(' . $fun . '((' . $name . '), ' . $str . ')): ?>' . $content . '<?php endif; ?>';\n        }\n        return $parseStr;\n    }\n\n    /**\n     * present标签解析\n     * 如果某个变量已经设置 则输出内容\n     * 格式： {present name=\"\" }content{/present}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagPresent($tag, $content)\n    {\n        $name     = $tag['name'];\n        $name     = $this->autoBuildVar($name);\n        $parseStr = '<?php if(isset(' . $name . ')): ?>' . $content . '<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * notpresent标签解析\n     * 如果某个变量没有设置，则输出内容\n     * 格式： {notpresent name=\"\" }content{/notpresent}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagNotpresent($tag, $content)\n    {\n        $name     = $tag['name'];\n        $name     = $this->autoBuildVar($name);\n        $parseStr = '<?php if(!isset(' . $name . ')): ?>' . $content . '<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * empty标签解析\n     * 如果某个变量为empty 则输出内容\n     * 格式： {empty name=\"\" }content{/empty}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagEmpty($tag, $content)\n    {\n        $name     = $tag['name'];\n        $name     = $this->autoBuildVar($name);\n        $parseStr = '<?php if(empty(' . $name . ') || ((' . $name . ' instanceof \\think\\Collection || ' . $name . ' instanceof \\think\\Paginator ) && ' . $name . '->isEmpty())): ?>' . $content . '<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * notempty标签解析\n     * 如果某个变量不为empty 则输出内容\n     * 格式： {notempty name=\"\" }content{/notempty}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagNotempty($tag, $content)\n    {\n        $name     = $tag['name'];\n        $name     = $this->autoBuildVar($name);\n        $parseStr = '<?php if(!(empty(' . $name . ') || ((' . $name . ' instanceof \\think\\Collection || ' . $name . ' instanceof \\think\\Paginator ) && ' . $name . '->isEmpty()))): ?>' . $content . '<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * 判断是否已经定义了该常量\n     * {defined name='TXT'}已定义{/defined}\n     * @param array $tag\n     * @param string $content\n     * @return string\n     */\n    public function tagDefined($tag, $content)\n    {\n        $name     = $tag['name'];\n        $parseStr = '<?php if(defined(\"' . $name . '\")): ?>' . $content . '<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * 判断是否没有定义了该常量\n     * {notdefined name='TXT'}已定义{/notdefined}\n     * @param array $tag\n     * @param string $content\n     * @return string\n     */\n    public function tagNotdefined($tag, $content)\n    {\n        $name     = $tag['name'];\n        $parseStr = '<?php if(!defined(\"' . $name . '\")): ?>' . $content . '<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * load 标签解析 {load file=\"/static/js/base.js\" /}\n     * 格式：{load file=\"/static/css/base.css\" /}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagLoad($tag, $content)\n    {\n        $file     = isset($tag['file']) ? $tag['file'] : $tag['href'];\n        $type     = isset($tag['type']) ? strtolower($tag['type']) : '';\n        $parseStr = '';\n        $endStr   = '';\n        // 判断是否存在加载条件 允许使用函数判断(默认为isset)\n        if (isset($tag['value'])) {\n            $name = $tag['value'];\n            $name = $this->autoBuildVar($name);\n            $name = 'isset(' . $name . ')';\n            $parseStr .= '<?php if(' . $name . '): ?>';\n            $endStr = '<?php endif; ?>';\n        }\n\n        // 文件方式导入\n        $array = explode(',', $file);\n        foreach ($array as $val) {\n            $type = strtolower(substr(strrchr($val, '.'), 1));\n            switch ($type) {\n                case 'js':\n                    $parseStr .= '<script type=\"text/javascript\" src=\"' . $val . '\"></script>';\n                    break;\n                case 'css':\n                    $parseStr .= '<link rel=\"stylesheet\" type=\"text/css\" href=\"' . $val . '\" />';\n                    break;\n                case 'php':\n                    $parseStr .= '<?php include \"' . $val . '\"; ?>';\n                    break;\n            }\n        }\n        return $parseStr . $endStr;\n    }\n\n    /**\n     * assign标签解析\n     * 在模板中给某个变量赋值 支持变量赋值\n     * 格式： {assign name=\"\" value=\"\" /}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagAssign($tag, $content)\n    {\n        $name = $this->autoBuildVar($tag['name']);\n        $flag = substr($tag['value'], 0, 1);\n        if ('$' == $flag || ':' == $flag) {\n            $value = $this->autoBuildVar($tag['value']);\n        } else {\n            $value = '\\'' . $tag['value'] . '\\'';\n        }\n        $parseStr = '<?php ' . $name . ' = ' . $value . '; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * define标签解析\n     * 在模板中定义常量 支持变量赋值\n     * 格式： {define name=\"\" value=\"\" /}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagDefine($tag, $content)\n    {\n        $name = '\\'' . $tag['name'] . '\\'';\n        $flag = substr($tag['value'], 0, 1);\n        if ('$' == $flag || ':' == $flag) {\n            $value = $this->autoBuildVar($tag['value']);\n        } else {\n            $value = '\\'' . $tag['value'] . '\\'';\n        }\n        $parseStr = '<?php define(' . $name . ', ' . $value . '); ?>';\n        return $parseStr;\n    }\n\n    /**\n     * for标签解析\n     * 格式：\n     * {for start=\"\" end=\"\" comparison=\"\" step=\"\" name=\"\"}\n     * content\n     * {/for}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagFor($tag, $content)\n    {\n        //设置默认值\n        $start      = 0;\n        $end        = 0;\n        $step       = 1;\n        $comparison = 'lt';\n        $name       = 'i';\n        $rand       = rand(); //添加随机数，防止嵌套变量冲突\n        //获取属性\n        foreach ($tag as $key => $value) {\n            $value = trim($value);\n            $flag  = substr($value, 0, 1);\n            if ('$' == $flag || ':' == $flag) {\n                $value = $this->autoBuildVar($value);\n            }\n\n            switch ($key) {\n                case 'start':\n                    $start = $value;\n                    break;\n                case 'end':\n                    $end = $value;\n                    break;\n                case 'step':\n                    $step = $value;\n                    break;\n                case 'comparison':\n                    $comparison = $value;\n                    break;\n                case 'name':\n                    $name = $value;\n                    break;\n            }\n        }\n\n        $parseStr = '<?php $__FOR_START_' . $rand . '__=' . $start . ';$__FOR_END_' . $rand . '__=' . $end . ';';\n        $parseStr .= 'for($' . $name . '=$__FOR_START_' . $rand . '__;' . $this->parseCondition('$' . $name . ' ' . $comparison . ' $__FOR_END_' . $rand . '__') . ';$' . $name . '+=' . $step . '){ ?>';\n        $parseStr .= $content;\n        $parseStr .= '<?php } ?>';\n        return $parseStr;\n    }\n\n    /**\n     * url函数的tag标签\n     * 格式：{url link=\"模块/控制器/方法\" vars=\"参数\" suffix=\"true或者false 是否带有后缀\" domain=\"true或者false 是否携带域名\" /}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagUrl($tag, $content)\n    {\n        $url    = isset($tag['link']) ? $tag['link'] : '';\n        $vars   = isset($tag['vars']) ? $tag['vars'] : '';\n        $suffix = isset($tag['suffix']) ? $tag['suffix'] : 'true';\n        $domain = isset($tag['domain']) ? $tag['domain'] : 'false';\n        return '<?php echo url(\"' . $url . '\",\"' . $vars . '\",' . $suffix . ',' . $domain . ');?>';\n    }\n\n    /**\n     * function标签解析 匿名函数，可实现递归\n     * 使用：\n     * {function name=\"func\" vars=\"$data\" call=\"$list\" use=\"&$a,&$b\"}\n     *      {if is_array($data)}\n     *          {foreach $data as $val}\n     *              {~func($val) /}\n     *          {/foreach}\n     *      {else /}\n     *          {$data}\n     *      {/if}\n     * {/function}\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content 标签内容\n     * @return string\n     */\n    public function tagFunction($tag, $content)\n    {\n        $name = !empty($tag['name']) ? $tag['name'] : 'func';\n        $vars = !empty($tag['vars']) ? $tag['vars'] : '';\n        $call = !empty($tag['call']) ? $tag['call'] : '';\n        $use  = ['&$' . $name];\n        if (!empty($tag['use'])) {\n            foreach (explode(',', $tag['use']) as $val) {\n                $use[] = '&' . ltrim(trim($val), '&');\n            }\n        }\n        $parseStr = '<?php $' . $name . '=function(' . $vars . ') use(' . implode(',', $use) . ') {';\n        $parseStr .= ' ?>' . $content . '<?php }; ';\n        $parseStr .= $call ? '$' . $name . '(' . $call . '); ?>' : '?>';\n        return $parseStr;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/think/view/driver/Php.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\view\\driver;\n\nuse think\\App;\nuse think\\exception\\TemplateNotFoundException;\nuse think\\Loader;\nuse think\\Log;\nuse think\\Request;\n\nclass Php\n{\n    // 模板引擎参数\n    protected $config = [\n        // 视图基础目录（集中式）\n        'view_base'   => '',\n        // 模板起始路径\n        'view_path'   => '',\n        // 模板文件后缀\n        'view_suffix' => 'php',\n        // 模板文件名分隔符\n        'view_depr'   => DS,\n    ];\n\n    public function __construct($config = [])\n    {\n        $this->config = array_merge($this->config, $config);\n    }\n\n    /**\n     * 检测是否存在模板文件\n     * @access public\n     * @param string $template 模板文件或者模板规则\n     * @return bool\n     */\n    public function exists($template)\n    {\n        if ('' == pathinfo($template, PATHINFO_EXTENSION)) {\n            // 获取模板文件名\n            $template = $this->parseTemplate($template);\n        }\n        return is_file($template);\n    }\n\n    /**\n     * 渲染模板文件\n     * @access public\n     * @param string    $template 模板文件\n     * @param array     $data 模板变量\n     * @return void\n     */\n    public function fetch($template, $data = [])\n    {\n        if ('' == pathinfo($template, PATHINFO_EXTENSION)) {\n            // 获取模板文件名\n            $template = $this->parseTemplate($template);\n        }\n        // 模板不存在 抛出异常\n        if (!is_file($template)) {\n            throw new TemplateNotFoundException('template not exists:' . $template, $template);\n        }\n        // 记录视图信息\n        App::$debug && Log::record('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]', 'info');\n        if (isset($data['template'])) {\n            $__template__ = $template;\n            extract($data, EXTR_OVERWRITE);\n            include $__template__;\n        } else {\n            extract($data, EXTR_OVERWRITE);\n            include $template;\n        }\n    }\n\n    /**\n     * 渲染模板内容\n     * @access public\n     * @param string    $content 模板内容\n     * @param array     $data 模板变量\n     * @return void\n     */\n    public function display($content, $data = [])\n    {\n        if (isset($data['content'])) {\n            $__content__ = $content;\n            extract($data, EXTR_OVERWRITE);\n            eval('?>' . $__content__);\n        } else {\n            extract($data, EXTR_OVERWRITE);\n            eval('?>' . $content);\n        }\n    }\n\n    /**\n     * 自动定位模板文件\n     * @access private\n     * @param string $template 模板文件规则\n     * @return string\n     */\n    private function parseTemplate($template)\n    {\n        if (empty($this->config['view_path'])) {\n            $this->config['view_path'] = App::$modulePath . 'view' . DS;\n        }\n\n        $request = Request::instance();\n        // 获取视图根目录\n        if (strpos($template, '@')) {\n            // 跨模块调用\n            list($module, $template) = explode('@', $template);\n        }\n        if ($this->config['view_base']) {\n            // 基础视图目录\n            $module = isset($module) ? $module : $request->module();\n            $path   = $this->config['view_base'] . ($module ? $module . DS : '');\n        } else {\n            $path = isset($module) ? APP_PATH . $module . DS . 'view' . DS : $this->config['view_path'];\n        }\n\n        $depr = $this->config['view_depr'];\n        if (0 !== strpos($template, '/')) {\n            $template   = str_replace(['/', ':'], $depr, $template);\n            $controller = Loader::parseName($request->controller());\n            if ($controller) {\n                if ('' == $template) {\n                    // 如果模板文件名为空 按照默认规则定位\n                    $template = str_replace('.', DS, $controller) . $depr . $request->action();\n                } elseif (false === strpos($template, $depr)) {\n                    $template = str_replace('.', DS, $controller) . $depr . $template;\n                }\n            }\n        } else {\n            $template = str_replace(['/', ':'], $depr, substr($template, 1));\n        }\n        return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.');\n    }\n\n    /**\n     * 配置模板引擎\n     * @access private\n     * @param string|array  $name 参数名\n     * @param mixed         $value 参数值\n     * @return void\n     */\n    public function config($name, $value = null)\n    {\n        if (is_array($name)) {\n            $this->config = array_merge($this->config, $name);\n        } elseif (is_null($value)) {\n            return isset($this->config[$name]) ? $this->config[$name] : null;\n        } else {\n            $this->config[$name] = $value;\n        }\n    }\n\n}\n"
  },
  {
    "path": "thinkphp/library/think/view/driver/Think.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think\\view\\driver;\n\nuse think\\App;\nuse think\\exception\\TemplateNotFoundException;\nuse think\\Loader;\nuse think\\Log;\nuse think\\Request;\nuse think\\Template;\n\nclass Think\n{\n    // 模板引擎实例\n    private $template;\n    // 模板引擎参数\n    protected $config = [\n        // 视图基础目录（集中式）\n        'view_base'   => '',\n        // 模板起始路径\n        'view_path'   => '',\n        // 模板文件后缀\n        'view_suffix' => 'html',\n        // 模板文件名分隔符\n        'view_depr'   => DS,\n        // 是否开启模板编译缓存,设为false则每次都会重新编译\n        'tpl_cache'   => true,\n    ];\n\n    public function __construct($config = [])\n    {\n        $this->config = array_merge($this->config, $config);\n        if (empty($this->config['view_path'])) {\n            $this->config['view_path'] = App::$modulePath . 'view' . DS;\n        }\n\n        $this->template = new Template($this->config);\n    }\n\n    /**\n     * 检测是否存在模板文件\n     * @access public\n     * @param string $template 模板文件或者模板规则\n     * @return bool\n     */\n    public function exists($template)\n    {\n        if ('' == pathinfo($template, PATHINFO_EXTENSION)) {\n            // 获取模板文件名\n            $template = $this->parseTemplate($template);\n        }\n        return is_file($template);\n    }\n\n    /**\n     * 渲染模板文件\n     * @access public\n     * @param string    $template 模板文件\n     * @param array     $data 模板变量\n     * @param array     $config 模板参数\n     * @return void\n     */\n    public function fetch($template, $data = [], $config = [])\n    {\n        if ('' == pathinfo($template, PATHINFO_EXTENSION)) {\n            // 获取模板文件名\n            $template = $this->parseTemplate($template);\n        }\n        // 模板不存在 抛出异常\n        if (!is_file($template)) {\n            throw new TemplateNotFoundException('template not exists:' . $template, $template);\n        }\n        // 记录视图信息\n        App::$debug && Log::record('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]', 'info');\n        $this->template->fetch($template, $data, $config);\n    }\n\n    /**\n     * 渲染模板内容\n     * @access public\n     * @param string    $template 模板内容\n     * @param array     $data 模板变量\n     * @param array     $config 模板参数\n     * @return void\n     */\n    public function display($template, $data = [], $config = [])\n    {\n        $this->template->display($template, $data, $config);\n    }\n\n    /**\n     * 自动定位模板文件\n     * @access private\n     * @param string $template 模板文件规则\n     * @return string\n     */\n    private function parseTemplate($template)\n    {\n        // 分析模板文件规则\n        $request = Request::instance();\n        // 获取视图根目录\n        if (strpos($template, '@')) {\n            // 跨模块调用\n            list($module, $template) = explode('@', $template);\n        }\n        if ($this->config['view_base']) {\n            // 基础视图目录\n            $module = isset($module) ? $module : $request->module();\n            $path   = $this->config['view_base'] . ($module ? $module . DS : '');\n        } else {\n            $path = isset($module) ? APP_PATH . $module . DS . 'view' . DS : $this->config['view_path'];\n        }\n\n        $depr = $this->config['view_depr'];\n        if (0 !== strpos($template, '/')) {\n            $template   = str_replace(['/', ':'], $depr, $template);\n            $controller = Loader::parseName($request->controller());\n            if ($controller) {\n                if ('' == $template) {\n                    // 如果模板文件名为空 按照默认规则定位\n                    $template = str_replace('.', DS, $controller) . $depr . $request->action();\n                } elseif (false === strpos($template, $depr)) {\n                    $template = str_replace('.', DS, $controller) . $depr . $template;\n                }\n            }\n        } else {\n            $template = str_replace(['/', ':'], $depr, substr($template, 1));\n        }\n        return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.');\n    }\n\n    /**\n     * 配置或者获取模板引擎参数\n     * @access private\n     * @param string|array  $name 参数名\n     * @param mixed         $value 参数值\n     * @return mixed\n     */\n    public function config($name, $value = null)\n    {\n        if (is_array($name)) {\n            $this->template->config($name);\n            $this->config = array_merge($this->config, $name);\n        } elseif (is_null($value)) {\n            return $this->template->config($name);\n        } else {\n            $this->template->$name = $value;\n            $this->config[$name]   = $value;\n        }\n    }\n\n    public function __call($method, $params)\n    {\n        return call_user_func_array([$this->template, $method], $params);\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/traits/controller/Jump.php",
    "content": "<?php\n\n/**\n * 用法：\n * load_trait('controller/Jump');\n * class index\n * {\n *     use \\traits\\controller\\Jump;\n *     public function index(){\n *         $this->error();\n *         $this->redirect();\n *     }\n * }\n */\nnamespace traits\\controller;\n\nuse think\\Config;\nuse think\\exception\\HttpResponseException;\nuse think\\Request;\nuse think\\Response;\nuse think\\response\\Redirect;\nuse think\\Url;\nuse think\\View as ViewTemplate;\n\ntrait Jump\n{\n    /**\n     * 操作成功跳转的快捷方法\n     * @access protected\n     * @param mixed     $msg 提示信息\n     * @param string    $url 跳转的URL地址\n     * @param mixed     $data 返回的数据\n     * @param integer   $wait 跳转等待时间\n     * @param array     $header 发送的Header信息\n     * @return void\n     */\n    protected function success($msg = '', $url = null, $data = '', $wait = 3, array $header = [])\n    {\n        $code = 1;\n        if (is_numeric($msg)) {\n            $code = $msg;\n            $msg  = '';\n        }\n        if (is_null($url) && isset($_SERVER[\"HTTP_REFERER\"])) {\n            $url = $_SERVER[\"HTTP_REFERER\"];\n        } elseif ('' !== $url) {\n            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : Url::build($url);\n        }\n        $result = [\n            'code' => $code,\n            'msg'  => $msg,\n            'data' => $data,\n            'url'  => $url,\n            'wait' => $wait,\n        ];\n\n        $type = $this->getResponseType();\n        if ('html' == strtolower($type)) {\n            $result = ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str'))\n                ->fetch(Config::get('dispatch_success_tmpl'), $result);\n        }\n        $response = Response::create($result, $type)->header($header);\n        throw new HttpResponseException($response);\n    }\n\n    /**\n     * 操作错误跳转的快捷方法\n     * @access protected\n     * @param mixed     $msg 提示信息\n     * @param string    $url 跳转的URL地址\n     * @param mixed     $data 返回的数据\n     * @param integer   $wait 跳转等待时间\n     * @param array     $header 发送的Header信息\n     * @return void\n     */\n    protected function error($msg = '', $url = null, $data = '', $wait = 3, array $header = [])\n    {\n        $code = 0;\n        if (is_numeric($msg)) {\n            $code = $msg;\n            $msg  = '';\n        }\n        if (is_null($url)) {\n            $url = Request::instance()->isAjax() ? '' : 'javascript:history.back(-1);';\n        } elseif ('' !== $url) {\n            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : Url::build($url);\n        }\n        $result = [\n            'code' => $code,\n            'msg'  => $msg,\n            'data' => $data,\n            'url'  => $url,\n            'wait' => $wait,\n        ];\n\n        $type = $this->getResponseType();\n        if ('html' == strtolower($type)) {\n            $result = ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str'))\n                ->fetch(Config::get('dispatch_error_tmpl'), $result);\n        }\n        $response = Response::create($result, $type)->header($header);\n        throw new HttpResponseException($response);\n    }\n\n    /**\n     * 返回封装后的API数据到客户端\n     * @access protected\n     * @param mixed     $data 要返回的数据\n     * @param integer   $code 返回的code\n     * @param mixed     $msg 提示信息\n     * @param string    $type 返回数据格式\n     * @param array     $header 发送的Header信息\n     * @return void\n     */\n    protected function result($data, $code = 0, $msg = '', $type = '', array $header = [])\n    {\n        $result = [\n            'code' => $code,\n            'msg'  => $msg,\n            'time' => $_SERVER['REQUEST_TIME'],\n            'data' => $data,\n        ];\n        $type     = $type ?: $this->getResponseType();\n        $response = Response::create($result, $type)->header($header);\n        throw new HttpResponseException($response);\n    }\n\n    /**\n     * URL重定向\n     * @access protected\n     * @param string         $url 跳转的URL表达式\n     * @param array|integer  $params 其它URL参数\n     * @param integer        $code http code\n     * @param array          $with 隐式传参\n     * @return void\n     */\n    protected function redirect($url, $params = [], $code = 302, $with = [])\n    {\n        $response = new Redirect($url);\n        if (is_integer($params)) {\n            $code   = $params;\n            $params = [];\n        }\n        $response->code($code)->params($params)->with($with);\n        throw new HttpResponseException($response);\n    }\n\n    /**\n     * 获取当前的response 输出类型\n     * @access protected\n     * @return string\n     */\n    protected function getResponseType()\n    {\n        $isAjax = Request::instance()->isAjax();\n        return $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type');\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/traits/model/SoftDelete.php",
    "content": "<?php\n\nnamespace traits\\model;\n\nuse think\\db\\Query;\n\ntrait SoftDelete\n{\n\n    /**\n     * 判断当前实例是否被软删除\n     * @access public\n     * @return boolean\n     */\n    public function trashed()\n    {\n        $field = $this->getDeleteTimeField();\n        if (!empty($this->data[$field])) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 查询软删除数据\n     * @access public\n     * @return Query\n     */\n    public static function withTrashed()\n    {\n        $model = new static();\n        $field = $model->getDeleteTimeField(true);\n        return $model->getQuery();\n    }\n\n    /**\n     * 只查询软删除数据\n     * @access public\n     * @return Query\n     */\n    public static function onlyTrashed()\n    {\n        $model = new static();\n        $field = $model->getDeleteTimeField(true);\n        return $model->getQuery()\n            ->useSoftDelete($field, ['not null', '']);\n    }\n\n    /**\n     * 删除当前的记录\n     * @access public\n     * @param bool  $force 是否强制删除\n     * @return integer\n     */\n    public function delete($force = false)\n    {\n        if (false === $this->trigger('before_delete', $this)) {\n            return false;\n        }\n        $name = $this->getDeleteTimeField();\n        if (!$force) {\n            // 软删除\n            $this->data[$name] = $this->autoWriteTimestamp($name);\n            $result            = $this->isUpdate()->save();\n        } else {\n            $result = $this->getQuery()->delete($this->data);\n        }\n\n        $this->trigger('after_delete', $this);\n        return $result;\n    }\n\n    /**\n     * 删除记录\n     * @access public\n     * @param mixed $data 主键列表 支持闭包查询条件\n     * @param bool  $force 是否强制删除\n     * @return integer 成功删除的记录数\n     */\n    public static function destroy($data, $force = false)\n    {\n        // 包含软删除数据\n        $query = self::withTrashed();\n        if (is_array($data) && key($data) !== 0) {\n            $query->where($data);\n            $data = null;\n        } elseif ($data instanceof \\Closure) {\n            call_user_func_array($data, [ & $query]);\n            $data = null;\n        } elseif (is_null($data)) {\n            return 0;\n        }\n\n        $resultSet = $query->select($data);\n        $count     = 0;\n        if ($resultSet) {\n            foreach ($resultSet as $data) {\n                $result = $data->delete($force);\n                $count += $result;\n            }\n        }\n        return $count;\n    }\n\n    /**\n     * 恢复被软删除的记录\n     * @access public\n     * @param array $where 更新条件\n     * @return integer\n     */\n    public function restore($where = [])\n    {\n        $name = $this->getDeleteTimeField();\n        if (empty($where)) {\n            $pk         = $this->getPk();\n            $where[$pk] = $this->getData($pk);\n        }\n        // 恢复删除\n        return $this->getQuery()\n            ->useSoftDelete($name, ['not null', ''])\n            ->where($where)\n            ->update([$name => null]);\n    }\n\n    /**\n     * 查询默认不包含软删除数据\n     * @access protected\n     * @param Query $query 查询对象\n     * @return void\n     */\n    protected function base($query)\n    {\n        $field = $this->getDeleteTimeField(true);\n        $query->useSoftDelete($field);\n    }\n\n    /**\n     * 获取软删除字段\n     * @access public\n     * @param bool  $read 是否查询操作 写操作的时候会自动去掉表别名\n     * @return string\n     */\n    protected function getDeleteTimeField($read = false)\n    {\n        $field = property_exists($this, 'deleteTime') && isset($this->deleteTime) ? $this->deleteTime : 'delete_time';\n        if (!strpos($field, '.')) {\n            $field = '__TABLE__.' . $field;\n        }\n        if (!$read && strpos($field, '.')) {\n            $array = explode('.', $field);\n            $field = array_pop($array);\n        }\n        return $field;\n    }\n}\n"
  },
  {
    "path": "thinkphp/library/traits/think/Instance.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace traits\\think;\n\nuse think\\Exception;\n\ntrait Instance\n{\n    protected static $instance = null;\n\n    /**\n     * @param array $options\n     * @return static\n     */\n    public static function instance($options = [])\n    {\n        if (is_null(self::$instance)) {\n            self::$instance = new self($options);\n        }\n        return self::$instance;\n    }\n\n    // 静态调用\n    public static function __callStatic($method, $params)\n    {\n        if (is_null(self::$instance)) {\n            self::$instance = new self();\n        }\n        $call = substr($method, 1);\n        if (0 === strpos($method, '_') && is_callable([self::$instance, $call])) {\n            return call_user_func_array([self::$instance, $call], $params);\n        } else {\n            throw new Exception(\"method not exists:\" . $method);\n        }\n    }\n}\n"
  },
  {
    "path": "thinkphp/phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit backupGlobals=\"false\"\n         backupStaticAttributes=\"false\"\n         bootstrap=\"tests/mock.php\"\n         colors=\"true\"\n         convertErrorsToExceptions=\"true\"\n         convertNoticesToExceptions=\"true\"\n         convertWarningsToExceptions=\"true\"\n         processIsolation=\"false\"\n         stopOnFailure=\"false\"\n         syntaxCheck=\"false\">\n    <testsuites>\n        <testsuite name=\"ThinkPHP Test Suite\">\n            <directory>./tests/thinkphp/</directory>\n        </testsuite>\n    </testsuites>\n    <listeners>\n        <listener class=\"JohnKary\\PHPUnit\\Listener\\SpeedTrapListener\" />\n    </listeners>\n    <filter>\n        <whitelist>\n            <directory suffix=\".php\">./</directory>\n            <exclude>\n                <directory suffix=\".php\">tests</directory>\n                <directory suffix=\".php\">vendor</directory>\n            </exclude>\n        </whitelist>\n    </filter>\n    <php>\n        <env name=\"APP_ENV\" value=\"testing\"/>\n        <env name=\"CACHE_DRIVER\" value=\"array\"/>\n        <env name=\"SESSION_DRIVER\" value=\"array\"/>\n        <env name=\"QUEUE_DRIVER\" value=\"sync\"/>\n    </php>\n</phpunit>\n"
  },
  {
    "path": "thinkphp/start.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace think;\n\n// ThinkPHP 引导文件\n// 加载基础文件\nrequire __DIR__ . '/base.php';\n// 执行应用\nApp::run()->send();\n"
  },
  {
    "path": "thinkphp/tpl/default_index.tpl",
    "content": "<?php\nnamespace {$app}\\{$module}{layer};\n\nclass Index{$suffix}\n{\n    public function index()\n    {\n        return '<style type=\"text/css\">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: \"Century Gothic\",\"Microsoft yahei\"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style=\"padding: 24px 48px;\"> <h1>:)</h1><p> ThinkPHP V5<br/><span style=\"font-size:30px\">十年磨一剑 - 为API开发设计的高性能框架</span></p><span style=\"font-size:22px;\">[ V5.0 版本由 <a href=\"http://www.qiniu.com\" target=\"qiniu\">七牛云</a> 独家赞助发布 ]</span></div><script type=\"text/javascript\" src=\"http://tajs.qq.com/stats?sId=9347272\" charset=\"UTF-8\"></script><script type=\"text/javascript\" src=\"http://ad.topthink.com/Public/static/client.js\"></script><thinkad id=\"ad_bd568ce7058a1091\"></thinkad>';\n    }\n}\n"
  },
  {
    "path": "thinkphp/tpl/dispatch_jump.tpl",
    "content": "{__NOLAYOUT__}<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n    <title>跳转提示</title>\n    <style type=\"text/css\">\n        *{ padding: 0; margin: 0; }\n        body{ background: #fff; font-family: \"Microsoft Yahei\",\"Helvetica Neue\",Helvetica,Arial,sans-serif; color: #333; font-size: 16px; }\n        .system-message{ padding: 24px 48px; }\n        .system-message h1{ font-size: 100px; font-weight: normal; line-height: 120px; margin-bottom: 12px; }\n        .system-message .jump{ padding-top: 10px; }\n        .system-message .jump a{ color: #333; }\n        .system-message .success,.system-message .error{ line-height: 1.8em; font-size: 36px; }\n        .system-message .detail{ font-size: 12px; line-height: 20px; margin-top: 12px; display: none; }\n    </style>\n</head>\n<body>\n    <div class=\"system-message\">\n        <?php switch ($code) {?>\n            <?php case 1:?>\n            <h1>:)</h1>\n            <p class=\"success\"><?php echo(strip_tags($msg));?></p>\n            <?php break;?>\n            <?php case 0:?>\n            <h1>:(</h1>\n            <p class=\"error\"><?php echo(strip_tags($msg));?></p>\n            <?php break;?>\n        <?php } ?>\n        <p class=\"detail\"></p>\n        <p class=\"jump\">\n            页面自动 <a id=\"href\" href=\"<?php echo($url);?>\">跳转</a> 等待时间： <b id=\"wait\"><?php echo($wait);?></b>\n        </p>\n    </div>\n    <script type=\"text/javascript\">\n        (function(){\n            var wait = document.getElementById('wait'),\n                href = document.getElementById('href').href;\n            var interval = setInterval(function(){\n                var time = --wait.innerHTML;\n                if(time <= 0) {\n                    location.href = href;\n                    clearInterval(interval);\n                };\n            }, 1000);\n        })();\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "thinkphp/tpl/page_trace.tpl",
    "content": "<div id=\"think_page_trace\" style=\"position: fixed;bottom:0;right:0;font-size:14px;width:100%;z-index: 999999;color: #000;text-align:left;font-family:'微软雅黑';\">\n    <div id=\"think_page_trace_tab\" style=\"display: none;background:white;margin:0;height: 250px;\">\n        <div id=\"think_page_trace_tab_tit\" style=\"height:30px;padding: 6px 12px 0;border-bottom:1px solid #ececec;border-top:1px solid #ececec;font-size:16px\">\n            <?php foreach ($trace as $key => $value) {?>\n            <span style=\"color:#000;padding-right:12px;height:30px;line-height:30px;display:inline-block;margin-right:3px;cursor:pointer;font-weight:700\"><?php echo $key ?></span>\n            <?php }?>\n        </div>\n        <div id=\"think_page_trace_tab_cont\" style=\"overflow:auto;height:212px;padding:0;line-height: 24px\">\n            <?php foreach ($trace as $info) {?>\n            <div style=\"display:none;\">\n                <ol style=\"padding: 0; margin:0\">\n                    <?php\n                    if (is_array($info)) {\n                        foreach ($info as $k => $val) {\n                            echo '<li style=\"border-bottom:1px solid #EEE;font-size:14px;padding:0 12px\">' . (is_numeric($k) ? '' : $k.' : ') . htmlentities(print_r($val,true), ENT_COMPAT, 'utf-8') . '</li>';\n                        }\n                    }\n                    ?>\n                </ol>\n            </div>\n            <?php }?>\n        </div>\n    </div>\n    <div id=\"think_page_trace_close\" style=\"display:none;text-align:right;height:15px;position:absolute;top:10px;right:12px;cursor:pointer;\"><img style=\"vertical-align:top;\" src=\"data:image/gif;base64,R0lGODlhDwAPAJEAAAAAAAMDA////wAAACH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MUQxMjc1MUJCQUJDMTFFMTk0OUVGRjc3QzU4RURFNkEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MUQxMjc1MUNCQUJDMTFFMTk0OUVGRjc3QzU4RURFNkEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoxRDEyNzUxOUJBQkMxMUUxOTQ5RUZGNzdDNThFREU2QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoxRDEyNzUxQUJBQkMxMUUxOTQ5RUZGNzdDNThFREU2QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAAAAAAALAAAAAAPAA8AAAIdjI6JZqotoJPR1fnsgRR3C2jZl3Ai9aWZZooV+RQAOw==\" /></div>\n</div>\n<div id=\"think_page_trace_open\" style=\"height:30px;float:right;text-align:right;overflow:hidden;position:fixed;bottom:0;right:0;color:#000;line-height:30px;cursor:pointer;\">\n    <div style=\"background:#232323;color:#FFF;padding:0 6px;float:right;line-height:30px;font-size:14px\"><?php echo \\think\\Debug::getUseTime().'s ';?></div>\n    <img width=\"30\" style=\"\" title=\"ShowPageTrace\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVERDVENkZGQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVERDVENzAwQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NURENUQ2RkRCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NURENUQ2RkVCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5fx6IRAAAMCElEQVR42sxae3BU1Rk/9+69+8xuNtkHJAFCSIAkhMgjCCJQUi0GtEIVbP8Qq9LH2No6TmfaztjO2OnUdvqHFMfOVFTqIK0vUEEeqUBARCsEeYQkEPJoEvIiELLvvc9z+p27u2F3s5tsBB1OZiebu5dzf7/v/L7f952zMM8cWIwY+Mk2ulCp92Fnq3XvnzArr2NZnYNldDp0Gw+/OEQ4+obQn5D+4Ubb22+YOGsWi/Todh8AHglKEGkEsnHBQ162511GZFgW6ZCBM9/W4H3iNSQqIe09O196dLKX7d1O39OViP/wthtkND62if/wj/DbMpph8BY/m9xy8BoBmQk+mHqZQGNy4JYRwCoRbwa8l4JXw6M+orJxpU0U6ToKy/5bQsAiTeokGKkTx46RRxxEUgrwGgF4MWNNEJCGgYTvpgnY1IJWg5RzfqLgvcIgktX0i8dmMlFA8qCQ5L0Z/WObPLUxT1i4lWSYDISoEfBYGvM+LlMQQdkLHoWRRZ8zYQI62Thswe5WTORGwNXDcGjqeOA9AF7B8rhzsxMBEoJ8oJKaqPu4hblHMCMPwl9XeNWyb8xkB/DDGYKfMAE6aFL7xesZ389JlgG3XHEMI6UPDOP6JHHu67T2pwNPI69mCP4rEaBDUAJaKc/AOuXiwH07VCS3w5+UQMAuF/WqGI+yFIwVNBwemBD4r0wgQiKoFZa00sEYTwss32lA1tPwVxtc8jQ5/gWCwmGCyUD8vRT0sHBFW4GJDvZmrJFWRY1EkrGA6ZB8/10fOZSSj0E6F+BSP7xidiIzhBmKB09lEwHPkG+UQIyEN44EBiT5vrv2uJXyPQqSqO930fxvcvwbR/+JAkD9EfASgI9EHlp6YiHO4W+cAB20SnrFqxBbNljiXf1Pl1K2S0HCWfiog3YlAD5RGwwxK6oUjTweuVigLjyB0mX410mAFnMoVK1lvvUvgt8fUJH0JVyjuvcmg4dE5mUiFtD24AZ4qBVELxXKS+pMxN43kSdzNwudJ+bQbLlmnxvPOQoCugSap1GnSRoG8KOiKbH+rIA0lEeSAg3y6eeQ6XI2nrYnrPM89bUTgI0Pdqvl50vlNbtZxDUBcLBK0kPd5jPziyLdojJIN0pq5/mdzwL4UVvVInV5ncQEPNOUxa9d0TU+CW5l+FoI0GSDKHVVSOs+0KOsZoxwOzSZNFGv0mQ9avyLCh2Hpm+70Y0YJoJVgmQv822wnDC8Miq6VjJ5IFed0QD1YiAbT+nQE8v/RMZfmgmcCRHIIu7Bmcp39oM9fqEychcA747KxQ/AEyqQonl7hATtJmnhO2XYtgcia01aSbVMenAXrIomPcLgEBA4liGBzFZAT8zBYqW6brI67wg8sFVhxBhwLwBP2+tqBQqqK7VJKGh/BRrfTr6nWL7nYBaZdBJHqrX3kPEPap56xwE/GvjJTRMADeMCdcGpGXL1Xh4ZL8BDOlWkUpegfi0CeDzeA5YITzEnddv+IXL+UYCmqIvqC9UlUC/ki9FipwVjunL3yX7dOTLeXmVMAhbsGporPfyOBTm/BJ23gTVehsvXRnSewagUfpBXF3p5pygKS7OceqTjb7h2vjr/XKm0ZofKSI2Q/J102wHzatZkJPYQ5JoKsuK+EoHJakVzubzuLQDepCKllTZi9AG0DYg9ZLxhFaZsOu7bvlmVI5oPXJMQJcHxHClSln1apFTvAimeg48u0RWFeZW4lVcjbQWZuIQK1KozZfIDO6CSQmQQXdpBaiKZyEWThVK1uEc6v7V7uK0ysduExPZx4vysDR+4SelhBYm0R6LBuR4PXts8MYMcJPsINo4YZCDLj0sgB0/vLpPXvA2Tn42Cv5rsLulGubzW0sEd3d4W/mJt2Kck+DzDMijfPLOjyrDhXSh852B+OvflqAkoyXO1cYfujtc/i3jJSAwhgfFlp20laMLOku/bC7prgqW7lCn4auE5NhcXPd3M7x70+IceSgZvNljCd9k3fLjYsPElqLR14PXQZqD2ZNkkrAB79UeJUebFQmXpf8ZcAQt2XrMQdyNUVBqZoUzAFyp3V3xi/MubUA/mCT4Fhf038PC8XplhWnCmnK/ZzyC2BSTRSqKVOuY2kB8Jia0lvvRIVoP+vVWJbYarf6p655E2/nANBMCWkgD49DA0VAMyI1OLFMYCXiU9bmzi9/y5i/vsaTpHPHidTofzLbM65vMPva9HlovgXp0AvjtaqYMfDD0/4mAsYE92pxa+9k1QgCnRVObCpojpzsKTPvayPetTEgBdwnssjuc0kOBFX+q3HwRQxdrOLAqeYRjkMk/trTSu2Z9Lik7CfF0AvjtqAhS4NHobGXUnB5DQs8hG8p/wMX1r4+8xkmyvQ50JVq72TVeXbz3HvpWaQJi57hJYTw4kGbtS+C2TigQUtZUX+X27QQq2ePBZBru/0lxTm8fOOQ5yaZOZMAV+he4FqIMB+LQB0UgMSajANX29j+vbmly8ipRvHeSQoQOkM5iFXcPQCVwDMs5RBCQmaPOyvbNd6uwvQJ183BZQG3Zc+Eiv7vQOKu8YeDmMcJlt2ckyftVeMIGLBCmdMHl/tFILYwGPjXWO3zOfSq/+om+oa7Mlh2fpSsRGLp7RAW3FUVjNHgiMhyE6zBFjM2BdkdJGO7nP1kJXWAtBuBpPIAu7f+hhu7bFXIuC5xWrf0X2xreykOsUyKkF2gwadbrXDcXrfKxR43zGcSj4t/cCgr+a1iy6EjE5GYktUCl9fwfMeylyooGF48bN2IGLTw8x7StS7sj8TF9FmPGWQhm3rRR+o9lhvjJvSYAdfDUevI1M6bnX/OwWaDMOQ8RPgKRo0eulBTdT8AW2kl8e9L7UHghHwMfLiZPNoSpx0yugpQZaFqKWqxVSM3a2pN1SAhC2jf94I7ybBI7EL5A2Wvu5ht3xsoEt4+Ay/abXgCQAxyOeDsDlTCQzy75ohcGgv9Tra9uiymRUYTLrswOLlCdfAQf7HPDQQ4ErAH5EDXB9cMxWYpjtXApRncojS0sbV/cCgHTHwGNBJy+1PQE2x56FpaVR7wfQGZ37V+V+19EiHNvR6q1fRUjqvbjbMq1/qfHxbTrE10ePY2gPFk48D2CVMTf1AF4PXvyYR9dV6Wf7H413m3xTWQvYGhQ7mfYwA5mAX+18Vue05v/8jG/fZX/IW5MKPKtjSYlt0ellxh+/BOCPAwYaeVr0QofZFxJWVWC8znG70au6llVmktsF0bfHF6k8fvZ5esZJbwHwwnjg59tXz6sL/P0NUZDuSNu1mnJ8Vab17+cy005A9wtOpp3i0bZdpJLUil00semAwN45LgEViZYe3amNye0B6A9chviSlzXVsFtyN5/1H3gaNmMpn8Fz0GpYFp6Zw615H/LpUuRQQDMCL82n5DpBSawkvzIdN2ypiT8nSLth8Pk9jnjwdFzH3W4XW6KMBfwB569NdcGX93mC16tTflcArcYUc/mFuYbV+8zY0SAjAVoNErNgWjtwumJ3wbn/HlBFYdxHvSkJJEc+Ngal9opSwyo9YlITX2C/P/+gf8sxURSLR+mcZUmeqaS9wrh6vxW5zxFCOqFi90RbDWq/YwZmnu1+a6OvdpvRqkNxxe44lyl4OobEnpKA6Uox5EfH9xzPs/HRKrTPWdIQrK1VZDU7ETiD3Obpl+8wPPCRBbkbwNtpW9AbBe5L1SMlj3tdTxk/9W47JUmqS5HU+JzYymUKXjtWVmT9RenIhgXc+nroWLyxXJhmL112OdB8GCsk4f8oZJucnvmmtR85mBn10GZ0EKSCMUSAR3ukcXd5s7LvLD3me61WkuTCpJzYAyRurMB44EdEJzTfU271lUJC03YjXJXzYOGZwN4D8eB5jlfLrdWfzGRW7icMPfiSO6Oe7s20bmhdgLX4Z23B+s3JgQESzUDiMboSzDMHFpNMwccGePauhfwjzwnI2wu9zKGgEFg80jcZ7MHllk07s1H+5yojtUQTlH4nFdLKTGwDmPbIklOb1L1zO4T6N8NCuDLFLS/C63c0eNRimZ++s5BMBHxU11jHchI9oFVUxRh/eMDzHEzGYu0Lg8gJ7oS/tFCwoic44fyUtix0n/46vP4bf+//BRgAYwDDar4ncHIAAAAASUVORK5CYII=\">\n</div>\n\n<script type=\"text/javascript\">\n    (function(){\n        var tab_tit  = document.getElementById('think_page_trace_tab_tit').getElementsByTagName('span');\n        var tab_cont = document.getElementById('think_page_trace_tab_cont').getElementsByTagName('div');\n        var open     = document.getElementById('think_page_trace_open');\n        var close    = document.getElementById('think_page_trace_close').children[0];\n        var trace    = document.getElementById('think_page_trace_tab');\n        var cookie   = document.cookie.match(/thinkphp_show_page_trace=(\\d\\|\\d)/);\n        var history  = (cookie && typeof cookie[1] != 'undefined' && cookie[1].split('|')) || [0,0];\n        open.onclick = function(){\n            trace.style.display = 'block';\n            this.style.display = 'none';\n            close.parentNode.style.display = 'block';\n            history[0] = 1;\n            document.cookie = 'thinkphp_show_page_trace='+history.join('|')\n        }\n        close.onclick = function(){\n            trace.style.display = 'none';\n            this.parentNode.style.display = 'none';\n            open.style.display = 'block';\n            history[0] = 0;\n            document.cookie = 'thinkphp_show_page_trace='+history.join('|')\n        }\n        for(var i = 0; i < tab_tit.length; i++){\n            tab_tit[i].onclick = (function(i){\n                return function(){\n                    for(var j = 0; j < tab_cont.length; j++){\n                        tab_cont[j].style.display = 'none';\n                        tab_tit[j].style.color = '#999';\n                    }\n                    tab_cont[i].style.display = 'block';\n                    tab_tit[i].style.color = '#000';\n                    history[1] = i;\n                    document.cookie = 'thinkphp_show_page_trace='+history.join('|')\n                }\n            })(i)\n        }\n        parseInt(history[0]) && open.click();\n        tab_tit[history[1]].click();\n    })();\n</script>\n"
  },
  {
    "path": "thinkphp/tpl/think_exception.tpl",
    "content": "<?php\n    if(!function_exists('parse_padding')){\n        function parse_padding($source)\n        {\n            $length  = strlen(strval(count($source['source']) + $source['first']));\n            return 40 + ($length - 1) * 8;\n        }\n    }\n\n    if(!function_exists('parse_class')){\n        function parse_class($name)\n        {\n            $names = explode('\\\\', $name);\n            return '<abbr title=\"'.$name.'\">'.end($names).'</abbr>';\n        }\n    }\n\n    if(!function_exists('parse_file')){\n        function parse_file($file, $line)\n        {\n            return '<a class=\"toggle\" title=\"'.\"{$file} line {$line}\".'\">'.basename($file).\" line {$line}\".'</a>';\n        }\n    }\n\n    if(!function_exists('parse_args')){\n        function parse_args($args)\n        {\n            $result = [];\n\n            foreach ($args as $key => $item) {\n                switch (true) {\n                    case is_object($item):\n                        $value = sprintf('<em>object</em>(%s)', parse_class(get_class($item)));\n                        break;\n                    case is_array($item):\n                        if(count($item) > 3){\n                            $value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3)));\n                        } else {\n                            $value = sprintf('[%s]', parse_args($item));\n                        }\n                        break;\n                    case is_string($item):\n                        if(strlen($item) > 20){\n                            $value = sprintf(\n                                '\\'<a class=\"toggle\" title=\"%s\">%s...</a>\\'',\n                                htmlentities($item),\n                                htmlentities(substr($item, 0, 20))\n                            );\n                        } else {\n                            $value = sprintf(\"'%s'\", htmlentities($item));\n                        }\n                        break;\n                    case is_int($item):\n                    case is_float($item):\n                        $value = $item;\n                        break;\n                    case is_null($item):\n                        $value = '<em>null</em>';\n                        break;\n                    case is_bool($item):\n                        $value = '<em>' . ($item ? 'true' : 'false') . '</em>';\n                        break;\n                    case is_resource($item):\n                        $value = '<em>resource</em>';\n                        break;\n                    default:\n                        $value = htmlentities(str_replace(\"\\n\", '', var_export(strval($item), true)));\n                        break;\n                }\n\n                $result[] = is_int($key) ? $value : \"'{$key}' => {$value}\";\n            }\n\n            return implode(', ', $result);\n        }\n    }\n?>\n<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <title><?php echo \\think\\Lang::get('System Error'); ?></title>\n    <meta name=\"robots\" content=\"noindex,nofollow\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <style>\n        /* Base */\n        body {\n            color: #333;\n            font: 14px Verdana, \"Helvetica Neue\", helvetica, Arial, 'Microsoft YaHei', sans-serif;\n            margin: 0;\n            padding: 0 20px 20px;\n            word-break: break-word;\n        }\n        h1{\n            margin: 10px 0 0;\n            font-size: 28px;\n            font-weight: 500;\n            line-height: 32px;\n        }\n        h2{\n            color: #4288ce;\n            font-weight: 400;\n            padding: 6px 0;\n            margin: 6px 0 0;\n            font-size: 18px;\n            border-bottom: 1px solid #eee;\n        }\n        h3.subheading {\n            color: #4288ce;\n            margin: 6px 0 0;\n            font-weight: 400;\n        }\n        h3{\n            margin: 12px;\n            font-size: 16px;\n            font-weight: bold;\n        }\n        abbr{\n            cursor: help;\n            text-decoration: underline;\n            text-decoration-style: dotted;\n        }\n        a{\n            color: #868686;\n            cursor: pointer;\n        }\n        a:hover{\n            text-decoration: underline;\n        }\n        .line-error{\n            background: #f8cbcb;\n        }\n\n        .echo table {\n            width: 100%;\n        }\n\n        .echo pre {\n            padding: 16px;\n            overflow: auto;\n            font-size: 85%;\n            line-height: 1.45;\n            background-color: #f7f7f7;\n            border: 0;\n            border-radius: 3px;\n            font-family: Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n        }\n\n        .echo pre > pre {\n            padding: 0;\n            margin: 0;\n        }\n        /* Layout */\n        .col-md-3 {\n            width: 25%;\n        }\n        .col-md-9 {\n            width: 75%;\n        }\n        [class^=\"col-md-\"] {\n            float: left;\n        }\n        .clearfix {\n            clear:both;\n        }\n        @media only screen \n        and (min-device-width : 375px) \n        and (max-device-width : 667px) { \n            .col-md-3,\n            .col-md-9 {\n                width: 100%;\n            }\n        }\n        /* Exception Info */\n        .exception {\n            margin-top: 20px;\n        }\n        .exception .message{\n            padding: 12px;\n            border: 1px solid #ddd;\n            border-bottom: 0 none;\n            line-height: 18px;\n            font-size:16px;\n            border-top-left-radius: 4px;\n            border-top-right-radius: 4px;\n            font-family: Consolas,\"Liberation Mono\",Courier,Verdana,\"微软雅黑\";\n        }\n\n        .exception .code{\n            float: left;\n            text-align: center;\n            color: #fff;\n            margin-right: 12px;\n            padding: 16px;\n            border-radius: 4px;\n            background: #999;\n        }\n        .exception .source-code{\n            padding: 6px;\n            border: 1px solid #ddd;\n\n            background: #f9f9f9;\n            overflow-x: auto;\n\n        }\n        .exception .source-code pre{\n            margin: 0;\n        }\n        .exception .source-code pre ol{\n            margin: 0;\n            color: #4288ce;\n            display: inline-block;\n            min-width: 100%;\n            box-sizing: border-box;\n        font-size:14px;\n            font-family: \"Century Gothic\",Consolas,\"Liberation Mono\",Courier,Verdana;\n            padding-left: <?php echo (isset($source) && !empty($source)) ? parse_padding($source) : 40;  ?>px;\n        }\n        .exception .source-code pre li{\n            border-left: 1px solid #ddd;\n            height: 18px;\n            line-height: 18px;\n        }\n        .exception .source-code pre code{\n            color: #333;\n            height: 100%;\n            display: inline-block;\n            border-left: 1px solid #fff;\n        font-size:14px;\n            font-family: Consolas,\"Liberation Mono\",Courier,Verdana,\"微软雅黑\";\n        }\n        .exception .trace{\n            padding: 6px;\n            border: 1px solid #ddd;\n            border-top: 0 none;\n            line-height: 16px;\n        font-size:14px;\n            font-family: Consolas,\"Liberation Mono\",Courier,Verdana,\"微软雅黑\";\n        }\n        .exception .trace ol{\n            margin: 12px;\n        }\n        .exception .trace ol li{\n            padding: 2px 4px;\n        }\n        .exception div:last-child{\n            border-bottom-left-radius: 4px;\n            border-bottom-right-radius: 4px;\n        }\n\n        /* Exception Variables */\n        .exception-var table{\n            width: 100%;\n            margin: 12px 0;\n            box-sizing: border-box;\n            table-layout:fixed;\n            word-wrap:break-word;            \n        }\n        .exception-var table caption{\n            text-align: left;\n            font-size: 16px;\n            font-weight: bold;\n            padding: 6px 0;\n        }\n        .exception-var table caption small{\n            font-weight: 300;\n            display: inline-block;\n            margin-left: 10px;\n            color: #ccc;\n        }\n        .exception-var table tbody{\n            font-size: 13px;\n            font-family: Consolas,\"Liberation Mono\",Courier,\"微软雅黑\";\n        }\n        .exception-var table td{\n            padding: 0 6px;\n            vertical-align: top;\n            word-break: break-all;\n        }\n        .exception-var table td:first-child{\n            width: 28%;\n            font-weight: bold;\n            white-space: nowrap;\n        }\n        .exception-var table td pre{\n            margin: 0;\n        }\n\n        /* Copyright Info */\n        .copyright{\n            margin-top: 24px;\n            padding: 12px 0;\n            border-top: 1px solid #eee;\n        }\n\n        /* SPAN elements with the classes below are added by prettyprint. */\n        pre.prettyprint .pln { color: #000 }  /* plain text */\n        pre.prettyprint .str { color: #080 }  /* string content */\n        pre.prettyprint .kwd { color: #008 }  /* a keyword */\n        pre.prettyprint .com { color: #800 }  /* a comment */\n        pre.prettyprint .typ { color: #606 }  /* a type name */\n        pre.prettyprint .lit { color: #066 }  /* a literal value */\n        /* punctuation, lisp open bracket, lisp close bracket */\n        pre.prettyprint .pun, pre.prettyprint .opn, pre.prettyprint .clo { color: #660 }\n        pre.prettyprint .tag { color: #008 }  /* a markup tag name */\n        pre.prettyprint .atn { color: #606 }  /* a markup attribute name */\n        pre.prettyprint .atv { color: #080 }  /* a markup attribute value */\n        pre.prettyprint .dec, pre.prettyprint .var { color: #606 }  /* a declaration; a variable name */\n        pre.prettyprint .fun { color: red }  /* a function name */\n    </style>\n</head>\n<body>\n    <div class=\"echo\">\n        <?php echo $echo;?>\n    </div>\n    <?php if(\\think\\App::$debug) { ?>\n    <div class=\"exception\">\n    <div class=\"message\">\n        \n            <div class=\"info\">\n                <div>\n                    <h2>[<?php echo $code; ?>] <?php echo sprintf('%s in %s', parse_class($name), parse_file($file, $line)); ?></h2>\n                </div>\n                <div><h1><?php echo nl2br(htmlentities($message)); ?></h1></div>\n            </div>\n        \n    </div>\n\t<?php if(!empty($source)){?>\n        <div class=\"source-code\">\n            <pre class=\"prettyprint lang-php\"><ol start=\"<?php echo $source['first']; ?>\"><?php foreach ((array) $source['source'] as $key => $value) { ?><li class=\"line-<?php echo $key + $source['first']; ?>\"><code><?php echo htmlentities($value); ?></code></li><?php } ?></ol></pre>\n        </div>\n\t<?php }?>\n        <div class=\"trace\">\n            <h2>Call Stack</h2>\n            <ol>\n                <li><?php echo sprintf('in %s', parse_file($file, $line)); ?></li>\n                <?php foreach ((array) $trace as $value) { ?>\n                <li>\n                <?php \n                    // Show Function\n                    if($value['function']){\n                        echo sprintf(\n                            'at %s%s%s(%s)', \n                            isset($value['class']) ? parse_class($value['class']) : '',\n                            isset($value['type'])  ? $value['type'] : '', \n                            $value['function'], \n                            isset($value['args'])?parse_args($value['args']):''\n                        );\n                    }\n\n                    // Show line\n                    if (isset($value['file']) && isset($value['line'])) {\n                        echo sprintf(' in %s', parse_file($value['file'], $value['line']));\n                    }\n                ?>\n                </li>\n                <?php } ?>\n            </ol>\n        </div>\n    </div>\n    <?php } else { ?>\n    <div class=\"exception\">\n        \n            <div class=\"info\"><h1><?php echo htmlentities($message); ?></h1></div>\n        \n    </div>\n    <?php } ?>\n    \n    <?php if(!empty($datas)){ ?>\n    <div class=\"exception-var\">\n        <h2>Exception Datas</h2>\n        <?php foreach ((array) $datas as $label => $value) { ?>\n        <table>\n            <?php if(empty($value)){ ?>\n            <caption><?php echo $label; ?><small>empty</small></caption>\n            <?php } else { ?>\n            <caption><?php echo $label; ?></caption>\n            <tbody>\n                <?php foreach ((array) $value as $key => $val) { ?>\n                <tr>\n                    <td><?php echo htmlentities($key); ?></td>\n                    <td>\n                        <?php \n                            if(is_array($val) || is_object($val)){ \n                                echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));\n                            } else if(is_bool($val)) { \n                                echo $val ? 'true' : 'false';\n                            } else if(is_scalar($val)) {\n                                echo htmlentities($val);\n                            } else {\n                                echo 'Resource';\n                            }\n                        ?>\n                    </td>\n                </tr>\n                <?php } ?>\n            </tbody>\n            <?php } ?>\n        </table>\n        <?php } ?>\n    </div>\n    <?php } ?>\n\n    <?php if(!empty($tables)){ ?>\n    <div class=\"exception-var\">\n        <h2>Environment Variables</h2>\n        <?php foreach ((array) $tables as $label => $value) { ?>\n        <div>\n            <?php if(empty($value)){ ?>\n            <div class=\"clearfix\">\n                <div class=\"col-md-3\"><strong><?php echo $label; ?></strong></div>\n                <div class=\"col-md-9\"><small>empty</small></div>\n            </div>\n            <?php } else { ?>\n            <h3 class=\"subheading\"><?php echo $label; ?></h3>\n            <div>\n                <?php foreach ((array) $value as $key => $val) { ?>\n                <div class=\"clearfix\">\n                    <div class=\"col-md-3\"><strong><?php echo htmlentities($key); ?></strong></div>\n                    <div class=\"col-md-9\"><small>\n                        <?php \n                            if(is_array($val) || is_object($val)){ \n                                echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));\n                            } else if(is_bool($val)) { \n                                echo $val ? 'true' : 'false';\n                            } else if(is_scalar($val)) {\n                                echo htmlentities($val);\n                            } else {\n                                echo 'Resource';\n                            }\n                        ?>\n                    </small></div>\n                </div>\n                <?php } ?>\n            </div>\n            <?php } ?>\n        </div>\n        <?php } ?>\n    </div>\n    <?php } ?>\n\n    <div class=\"copyright\">\n        <a title=\"官方网站\" href=\"http://www.thinkphp.cn\">ThinkPHP</a> \n        <span>V<?php echo THINK_VERSION; ?></span> \n        <span>{ 十年磨一剑-为API开发设计的高性能框架 }</span>\n    </div>\n    <?php if(\\think\\App::$debug) { ?>\n    <script>\n        var LINE = <?php echo $line; ?>;\n\n        function $(selector, node){\n            var elements;\n\n            node = node || document;\n            if(document.querySelectorAll){\n                elements = node.querySelectorAll(selector);\n            } else {\n                switch(selector.substr(0, 1)){\n                    case '#':\n                        elements = [node.getElementById(selector.substr(1))];\n                        break;\n                    case '.':\n                        if(document.getElementsByClassName){\n                            elements = node.getElementsByClassName(selector.substr(1));\n                        } else {\n                            elements = get_elements_by_class(selector.substr(1), node);\n                        }\n                        break;\n                    default:\n                        elements = node.getElementsByTagName();\n                }\n            }\n            return elements;\n\n            function get_elements_by_class(search_class, node, tag) {\n                var elements = [], eles, \n                    pattern  = new RegExp('(^|\\\\s)' + search_class + '(\\\\s|$)');\n\n                node = node || document;\n                tag  = tag  || '*';\n\n                eles = node.getElementsByTagName(tag);\n                for(var i = 0; i < eles.length; i++) {\n                    if(pattern.test(eles[i].className)) {\n                        elements.push(eles[i])\n                    }\n                }\n\n                return elements;\n            }\n        }\n\n        $.getScript = function(src, func){\n            var script = document.createElement('script');\n            \n            script.async  = 'async';\n            script.src    = src;\n            script.onload = func || function(){};\n            \n            $('head')[0].appendChild(script);\n        }\n\n        ;(function(){\n            var files = $('.toggle');\n            var ol    = $('ol', $('.prettyprint')[0]);\n            var li    = $('li', ol[0]);   \n\n            // 短路径和长路径变换\n            for(var i = 0; i < files.length; i++){\n                files[i].ondblclick = function(){\n                    var title = this.title;\n\n                    this.title = this.innerHTML;\n                    this.innerHTML = title;\n                }\n            }\n\n            // 设置出错行\n            var err_line = $('.line-' + LINE, ol[0])[0];\n            err_line.className = err_line.className + ' line-error';\n\n            $.getScript('//cdn.bootcss.com/prettify/r298/prettify.min.js', function(){\n                prettyPrint();\n\n                // 解决Firefox浏览器一个很诡异的问题\n                // 当代码高亮后，ol的行号莫名其妙的错位\n                // 但是只要刷新li里面的html重新渲染就没有问题了\n                if(window.navigator.userAgent.indexOf('Firefox') >= 0){\n                    ol[0].innerHTML = ol[0].innerHTML;\n                }\n            });\n\n        })();\n    </script>\n    <?php } ?>\n</body>\n</html>\n"
  },
  {
    "path": "vendor/.gitignore",
    "content": "*\n!.gitignore"
  }
]