[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\ntest/\n\n*.exe\n*.test\ndata/\ndest/\nhosts_*\nconf/*\nfile/\n.*.html\n.DS_Store\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "2016-07-27\n   1. 升级依赖   \n\n2016-07-27\n    1. version 0.5.2\n    2. 修复文件上传页面错误\n    3. 更新lib otto ，boltdb 为最新版本\n    \n2016-03-25\n    1.版本号升级为0.5.1\n    2.改进request动态修改引擎并发异常问题\n    \n2014-12-27\n\t1.版本号升级为0.4.7\n\t2.添加adminPort配置项，以独立的端口提供给管理界面\n\n2014-12-17\n\t1.静态资源使用goassest方式而不使用之前的读取zip的方式\n\t\n2014-11-08\n\t1.重构代理处理逻辑，改进Upgrade代理协议\n\t2.会话详情页面展现请求时间\n\t3.upgrade结束的时候也记录一条response 以方便查看何时断开连接\n\t\n2014-09-27\n    1.http session list support local filter\n    \n    \n2014-09-14\n    1.downgrade the socket.io lib\n    \n2014-08-14\n   1.emit data with base64encode\n   2.fix some url has no schema\n   \n2014-08-10\n   1.websocket proxy support\n   \n2014-08-06\n   1.update socket.io\n   \n2014-07-19\n   1.修复监听端口为80时不能查看会话列表的问题\n   2.完善帮助说明\n\n2014-07-15\n   1.get和post参数支持重写\n   2.重写请求出现错误自己返回502错误\n\n2014-07-12 \n   1.认证机制升级，新认证机制：一个ip第一次访问的时候会要求登录，若没有输入登录信息也跳过。  \n   2.管理员用户（登录后）在session filter 输入user：any 可以查看到所有的会话信息  \n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 du\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README-en.md",
    "content": "pproxy 0.5.2\n======\nHTTP protocol analysis tool.  \n\n\n\nfeatures：\n<pre>\n1.url redirect\n   redirect *http://www.baidu.com/s?wd=pproxy* to  *http://m.baidu.com/s?wd=pproxy*\n   redirect  *ws://www.test.com/a* to  *ws://www.example.com/b*\n   \n2.form dynamic modification  \n   get、post and header all can modify  \n   \n3.hosts\n  www.baidu.com to 127.0.0.1  \n  or www.baidu.com:81 to 192.168.1.2:8080 ,and only  takes effect on port 81  \n  \n4.view request and response detail\n   form params，header and all response and easy to share\n   \n5.auth sup\n   http Basic or only try basic auth at first request\n   \n6.replay\n   can modify the get、post、header params and replay the request\n\n7.parent proxy\n  \n</pre>\n\nuse javascript code as config to modify the request params:\n```\nif(req.host==\"www.baidu.com\"){\n   req.host=\"www.163.com\"\n   req.host_addr=\"127.0.0.0:81\" // send req to 127.0.0.1:81\n}\n```\nor：\n```\nif(req.host.indexOf(\"baidu.com\")>-1){\n  req.host_addr=\"127.0.0.0:81\"\n}\n```\n\nrequest params dump：\n```\n#url : http://www.example.com/album/list?cid=126\n#request has these attrs：\nschema : http\nhost : www.example.com\nport : 80\npath : /album/list\nget: {cid:[123]}\npost: {}\nusername : \npassword : \nmethod: GET\nform_get  : {add:function(k,v){},set:function(k,v){},get:function(k){},len:function(){}} \nform_post : {add:function(k,v){},set:function(k,v){},get:function(k){},len:function(){}}\n\nhost_addr: #modify hosts eg:127.0.0.1:3218\n\n#note get and post value is array\n#form_get: helper function for get params\n#form_post: helper function for post params\n```\n\n\nhosts config demo:\n```\nwww.baidu.com 127.0.0.1\nwww.baidu.com:81 10.0.2.2:8080\n```\n\ndisable req_rewrite.js  \nfirst line ```//ignore```\n\n\nreq_rewrite.js支持不同用户设置不同的规则。默认使用当前验证使用用户名的规则，若无则使用默认的。  \n\nconfigs：\n```\nconf/\n├── pproxy.conf          #server config\n├── hosts_8080           #hosts for 8080\n├── req_rewrite_8080.js  #8080端口server的url重写规则\n├── hosts_8081\n├── req_rewrite_8081.js\n└── users                #全局帐号配置文件\n```\n\nusers配置:\n```\n#帐号 admin，密码 是 psw,是管理员帐号\nname:admin psw:psw is_admin:admin\n\n#密码也可以存储为md5值，使用  psw_md5：32位md密码\nname:admin_sec psw_md5:7bb483729b5a8e26f73e1831cde5b842 is_admin:admin\n```\n可以在线修改配置时必须使用管理员帐号登录\n\n配置文件示例:\n```\n\nport : 8080\n\ntitle : demo\nnotice :notice notice\n\n#数据存放目录，相对于当前配置的路径\ndataDir : ../data/\n\n#数据存放天数，0为永久存储（目前只在重启的时候会进行数据清理）\ndataStoreDay : 15\n\n#代理服务认证方式\n#options:{none : 无认证,basic:http basic ,basic_try:尝试httpBasic认证 ,basic_any:任意帐号}\nauthType : none\n\n#那些request和response数据进行存储\n#options:{ all : 所有   only_broadcast : 发送到session list的才存储}\nresponseSave : only_broadcast\n\n#session列表查看数据\n# options :{ all:所有人可见 ip_or_user : 输入正确的ip或者user后可见}\nsessionView : all\n\n#父级代理\n#eg http://10.10.2.2:3128 or http://name:psw@10.10.2.2:3128\n# http://pass:pass@10.10.2.2:3128 the user and psw will pass through to the parent proxy\nparentProxy:\n```\n"
  },
  {
    "path": "README.md",
    "content": "pproxy 0.5.2\n======\n## intro\nHTTP 协议抓包代理程序, HTTP 协议调试工具。  \n采用 Go 编写，采用 BS 模式(s-代理程序，b-会话查看、配置管理等功能)  \n\n0.4.2版本已经支持websocket代理，以及重定向(和普通http请求一样使用)  \n\n0.5 版本是对底层存储进行了替换，并且尝试支持https抓包\n\n## install\n\n已经安装go的用户直接安装：  \n>go install  github.com/hidu/pproxy@master\n\n## 功能特性\n<pre>\n1.url重定向\n   如把 http://www.baidu.com/s?wd=pproxy 修改为 http://m.baidu.com/s?wd=pproxy\n   或者把 ws://www.test.com/a 重定向到 ws://www.example.com/b\n   \n2.form表单动态修改  \n   get、post可以动态修改（增删改）  \n   \n3.hosts文件支持\n  相当于 修改host或者dns 如  \n  将www.baidu.com 请求全部发往127.0.0.1  \n  将www.baidu.com:81 请求全部发往192.168.1.2:8080  \n  \n4.可查看request 和response详情\n   form表单参数，header等都可以很方便的看到\n   \n5.登录认证支持\n   支持httpBasic认证\n   \n6.replay功能\n   可以修改request的参数（get、post、header）\n\n7.父级代理\n  \n</pre>\n\n## 配置\n\n### rewrite req\n使用javascript来配置重定向功能，如\n```\nif(req.host==\"www.baidu.com\"){\n   req.host=\"www.163.com\"\n   req.host_addr=\"127.0.0.0:81\" // send req to 127.0.0.1:81\n}\n```\n当然也可以这样：\n```\nif(req.host.indexOf(\"baidu.com\")>-1){\n  req.host_addr=\"127.0.0.0:81\"\n}\n```\n\n### req变量示例\n```\n#url : http://www.example.com/album/list?cid=126\n#req对象有如下一下属性：\nschema : http\nhost : www.example.com\nport : 80\npath : /album/list\nget: {cid:[123]}\npost: {}\nusername : \npassword : \nmethod: GET\nform_get  : {add:function(k,v){},set:function(k,v){},get:function(k){},len:function(){}} \nform_post : {add:function(k,v){},set:function(k,v){},get:function(k){},len:function(){}}\n\nhost_addr: #修改该请求的host是使用，如 127.0.0.1:3218\n\n#注意 get 和post的值是数组，如上cid参数\n#form_get 用于更方便的操作  get参数对象\n#form_post 用于更方便的操作 post参数对象\n```\n\n### hosts\n增强的hosts文件使用:\n```\nwww.baidu.com 127.0.0.1\nwww.baidu.com:81 10.0.2.2:8080\n```\n\n### other\n忽略禁用req_rewrite.js  \n在js文件的第一行内容写入 ```//ignore```\n\nreq_rewrite.js支持不同用户设置不同的规则。默认使用当前验证使用用户名的规则，若无则使用默认的。  \n\n### 配置文件结构：\n```\nconf/\n├── pproxy.conf          #server的配置\n├── hosts_8080           #8080端口server的hosts规则\n├── req_rewrite_8080.js  #8080端口server的url重写规则\n├── hosts_8081\n├── req_rewrite_8081.js\n└── users                #全局帐号配置文件\n```\n\n### users配置:\n```\n#帐号 admin，密码 是 psw,是管理员帐号\nname:admin psw:psw is_admin:admin\n\n#密码也可以存储为md5值，使用  psw_md5：32位md密码\nname:admin_sec psw_md5:7bb483729b5a8e26f73e1831cde5b842 is_admin:admin\n```\n可以在线修改配置时必须使用管理员帐号登录\n\n### 配置文件示例(pproxy.conf):\n```\n#提供代理服务的端口\nport : 8080\n\n#管理界面的端口，为0表示和代理服务使用相同的端口,eg:8081\nadminPort : 0\n\ntitle : demo\nnotice :notice notice\n\n#数据存放目录，相对于当前配置的路径\ndataDir : ../data/\n\n#数据存放天数，0为永久存储（目前只在重启的时候会进行数据清理）\ndataStoreDay : 15\n\n#代理服务认证方式\n#options:{none : 无认证,basic:http basic ,basic_try:尝试httpBasic认证 ,basic_any:任意帐号}\nauthType : none\n\n#那些request和response数据进行存储\n#options:{ all : 所有   only_broadcast : 发送到session list的才存储}\nresponseSave : only_broadcast\n\n#session列表查看数据\n# options :{ all:所有人可见 ip_or_user : 输入正确的ip或者user后可见}\nsessionView : all\n\n#父级代理\n#eg http://10.10.2.2:3128 or http://name:psw@10.10.2.2:3128\n# http://pass:pass@10.10.2.2:3128 the user and psw will pass through to the parent proxy\nparentProxy:\n\n\n#是否使用中间人方式对https进行抓包，若启用的话 需要客户端按照证书-/res/private/client_cert.pem\n#pproxy内置默认证书存放在/res/private目录中\n#options:{on:启用  off:禁用}\nssl : on\n\n#ssl 服务端秘钥文件地址，为空则使用默认内置的 /res/private/server_key.pem\nssl_server_key: \n#ssl 公钥地址 ，为空则使用默认内置的 /res/private/client_cert.pem\nssl_client_cert :\n```\n\n## (管理)web查看界面\n方式1： 直接访问 http://serverHost:port  \n方式2： 直接访问 http://serverHost:adminPort  \n方式3： 浏览器设置http代理 serverHost:port，访问 http://pproxy.man 或者 http://pproxy.com  \n\n# 其他\n## 如何自己修改源码中的静态资源？\n该项目的静态资源（res目录中的所有内容）都编译到go文件中去了，可以处理即可:  \n1. 安装goassest工具：\n```\ngo get -u github.com/hidu/goassest\n```\n2.到pproxy代码根目录下运行命令：\n```\ngoassest\n```\n\n调试过程中可以添加参数  `-assest_direct` 可以让静态资源实时生效而不需要重新编译静态资源：\n```\ngo run proxy_main.go -assest_direct\n```\n"
  },
  {
    "path": "assest.json",
    "content": "{\n  \"src\":\"res\",\n  \"dest\":\"serve/assest.go\",\n  \"package\":\"serve\"\n}\n"
  },
  {
    "path": "build.sh",
    "content": "#!/bin/bash\n# build for window: build.sh windows\n# default linux\n#./gox -build-toolchain\n\nset -e\ncd $(dirname $0)\n\n#export GOPATH=`readlink -f Godeps/_workspace`:$GOPATH\n\nexport GO15VENDOREXPERIMENT=1\n\ngo install"
  },
  {
    "path": "fmt.sh",
    "content": "#/bin/bash\ncd $(dirname $0)\ncd serve\n#gofmt -tabs=false -w=true -tabwidth=4 .\ngofmt -w=true -s=true .\n\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/hidu/pproxy\n\ngo 1.23\n\nrequire (\n\tgithub.com/Unknwon/goconfig v1.0.0\n\tgithub.com/boltdb/bolt v1.3.1\n\tgithub.com/elazarl/goproxy v0.0.0-20241219141958-0cbc93263399\n\tgithub.com/googollee/go-socket.io v0.9.1\n\tgithub.com/hidu/goutils v0.0.2\n\tgithub.com/robertkrimen/otto v0.5.1\n)\n\nrequire (\n\tgithub.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect\n\tgithub.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac // indirect\n\tgithub.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect\n\tgolang.org/x/net v0.33.0 // indirect\n\tgolang.org/x/sys v0.28.0 // indirect\n\tgolang.org/x/text v0.21.0 // indirect\n\tgopkg.in/sourcemap.v1 v1.0.5 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/Unknwon/goconfig v1.0.0 h1:9IAu/BYbSLQi8puFjUQApZTxIHqSwrj5d8vpP8vTq4A=\ngithub.com/Unknwon/goconfig v1.0.0/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=\ngithub.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=\ngithub.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=\ngithub.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=\ngithub.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/elazarl/goproxy v0.0.0-20241219141958-0cbc93263399 h1:WBf0ImRm78m/cgOOob9PUyQdYYod2luQA6fs+OqAjbw=\ngithub.com/elazarl/goproxy v0.0.0-20241219141958-0cbc93263399/go.mod h1:3tPvP6c6GrQS4u4TJEbOoqGC2wDNMLra3t6AXWwtL0M=\ngithub.com/elazarl/goproxy/ext v0.0.0-20241217120900-7711dfa3811c h1:R+i10jtNSzKJKqEZAYJnR9M8y14k0zrNHqD1xkv/A2M=\ngithub.com/elazarl/goproxy/ext v0.0.0-20241217120900-7711dfa3811c/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=\ngithub.com/googollee/go-socket.io v0.9.1 h1:KYsu63c3H5SaeQ3MDlHSTE/LJnwok2SH1M5wy4ZaYD0=\ngithub.com/googollee/go-socket.io v0.9.1/go.mod h1:Q0CvnKmaZNgDXIi85at4eLadAOS1hWDLaDATQpuH3i4=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=\ngithub.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/hidu/goutils v0.0.2 h1:ZjwXZhuWXZjzQ4dHoFo2iN6oDXH1TCudQZ0V2vdAUfQ=\ngithub.com/hidu/goutils v0.0.2/go.mod h1:m13DejGt6FVHM+taWpMHpavxBRZnnQBZeDJyB/YsyRI=\ngithub.com/howeyc/fsnotify v0.9.0/go.mod h1:41HzSPxBGeFRQKEEwgh49TRw/nKBsYZ2cF1OzPjSJsA=\ngithub.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/robertkrimen/otto v0.5.1 h1:avDI4ToRk8k1hppLdYFTuuzND41n37vPGJU7547dGf0=\ngithub.com/robertkrimen/otto v0.5.1/go.mod h1:bS433I4Q9p+E5pZLu7r17vP6FkE6/wLxBdmKjoqJXF8=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac h1:wbW+Bybf9pXxnCFAOWZTqkRjAc7rAIwo2e1ArUhiHxg=\ngithub.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=\ngithub.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=\ngithub.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=\ngithub.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=\ngolang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=\ngolang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=\ngolang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=\ngopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/hidu/pproxy/serve\"\n)\n\nvar configPath = flag.String(\"conf\", \"./conf/pproxy.conf\", \"pproxy's config file\")\nvar port = flag.Int(\"port\", 0, \"proxy port\")\nvar vv = flag.Bool(\"vv\", false, \"debug,log request with more detail\")\nvar showConf = flag.Bool(\"demo_conf\", false, \"show default conf\")\n\nvar version = flag.Bool(\"v\", false, \"show version\")\n\nfunc init() {\n\tdf := flag.Usage\n\n\tflag.Usage = func() {\n\t\tdf()\n\t\tfmt.Fprintln(os.Stderr, \"\\n HTTP protocol analysis tool\\n https://github.com/hidu/pproxy/\\n\")\n\t}\n}\n\nfunc main() {\n\tflag.Parse()\n\n\tif *showConf {\n\t\tdemoConf := serve.GetDemoConf()\n\t\tfmt.Println(demoConf)\n\t\tos.Exit(0)\n\t}\n\n\tif *version {\n\t\tfmt.Println(\"pproxy version:\", serve.GetVersion())\n\t\tos.Exit(0)\n\t}\n\n\tlog.SetFlags(log.Lshortfile | log.LstdFlags | log.Ldate)\n\tser, err := serve.NewProxyServe(*configPath, *port)\n\tif err != nil {\n\t\tfmt.Println(\"start pproxy failed\", err)\n\t\tos.Exit(2)\n\t}\n\tser.Debug = *vv\n\tser.Start()\n}\n"
  },
  {
    "path": "res/conf/demo.conf",
    "content": "##########################################################\n#                  pproxy demo conf                      #\n##########################################################\n\n#提供代理服务的端口\nport : 8080\n\n#管理界面的端口，为0表示和代理服务使用相同的端口\nadminPort : 0\n\ntitle : hello pproxy\nnotice : notice notice\n\n#数据存放目录，相对于当前配置的路径\ndataDir : ../data/\n\n#静态文件存放目录\nfileDir:  ../file/\n\n\n#数据存放天数，0为永久存储（目前只在重启的时候会进行数据清理）\ndataStoreDay : 15\n\n#代理服务认证方式\n#options:{none : 无认证,basic:http basic ,basic_try:尝试httpBasic认证 ,basic_any:任意帐号}\nauthType : none\n\n#那些request和response数据进行存储\n#options:{ all : 所有   only_broadcast : 发送到session list的才存储}\nresponseSave : only_broadcast\n\n#session列表查看数据\n# options :{ all:所有人可见 ip_or_user : 输入正确的ip或者user后可见}\nsessionView : all\n\n#eg http://10.10.2.2:3128 or http://name:psw@10.10.2.2:3128\n# http://name:psw@10.10.2.2:3128 the user and psw will pass through to the parent proxy\nparentProxy:"
  },
  {
    "path": "res/css/flat.css",
    "content": ".dropdown-arrow-inverse {\n  border-bottom-color: #34495e !important;\n  border-top-color: #34495e !important;\n}\na {\n  color: #428bca;\n  text-decoration: none;\n  -webkit-transition: 0.25s;\n  transition: 0.25s;\n}\na:hover,\na:focus {\n  color: #428bca;\n  text-decoration: none;\n}\na:focus {\n  outline: none;\n}\n.img-rounded {\n  border-radius: 6px;\n}\n.img-thumbnail {\n  padding: 4px;\n  line-height: 1.72222;\n  background-color: #ffffff;\n  border: 2px solid #bdc3c7;\n  border-radius: 6px;\n  -webkit-transition: all 0.25s ease-in-out;\n  transition: all 0.25s ease-in-out;\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n}\n.img-comment {\n  font-size: 15px;\n  line-height: 1.2;\n  font-style: italic;\n  margin: 24px 0;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n  font-family: inherit;\n  font-weight: 700;\n  line-height: 1.1;\n  color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small {\n  color: #e7e9ec;\n}\nh1,\nh2,\nh3 {\n  margin-top: 30px;\n  margin-bottom: 15px;\n}\nh4,\nh5,\nh6 {\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\nh6 {\n  font-weight: normal;\n}\nh1,\n.h1 {\n  font-size: 61px;\n}\nh2,\n.h2 {\n  font-size: 53px;\n}\nh3,\n.h3 {\n  font-size: 40px;\n}\nh4,\n.h4 {\n  font-size: 29px;\n}\nh5,\n.h5 {\n  font-size: 28px;\n}\nh6,\n.h6 {\n  font-size: 24px;\n}\np {\n  font-size: 18px;\n  line-height: 1.72222;\n  margin: 0 0 15px;\n}\n.lead {\n  margin-bottom: 30px;\n  font-size: 28px;\n  line-height: 1.46428571;\n  font-weight: 300;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 30.006px;\n  }\n}\nsmall,\n.small {\n  font-size: 83%;\n  line-height: 2.067;\n}\n.text-muted {\n  color: #bdc3c7;\n}\n.text-inverse {\n  color: #ffffff;\n}\n.text-primary {\n  color: #428bca;\n}\na.text-primary:hover {\n  color: #15967d;\n}\n.text-warning {\n  color: #f1c40f;\n}\na.text-warning:hover {\n  color: #c19d0c;\n}\n.text-danger {\n  color: #e74c3c;\n}\na.text-danger:hover {\n  color: #b93d30;\n}\n.text-success {\n  color: #2ecc71;\n}\na.text-success:hover {\n  color: #25a35a;\n}\n.text-info {\n  color: #3498db;\n}\na.text-info:hover {\n  color: #2a7aaf;\n}\n.bg-primary {\n  color: #ffffff;\n  background-color: #34495e;\n}\na.bg-primary:hover {\n  background-color: #222f3d;\n}\n.bg-success {\n  background-color: #dff0d8;\n}\na.bg-success:hover {\n  background-color: #c1e2b3;\n}\n.bg-info {\n  background-color: #d9edf7;\n}\na.bg-info:hover {\n  background-color: #afd9ee;\n}\n.bg-warning {\n  background-color: #fcf8e3;\n}\na.bg-warning:hover {\n  background-color: #f7ecb5;\n}\n.bg-danger {\n  background-color: #f2dede;\n}\na.bg-danger:hover {\n  background-color: #e4b9b9;\n}\n.page-header {\n  padding-bottom: 14px;\n  margin: 60px 0 30px;\n  border-bottom: 1px solid #e7e9ec;\n}\nul,\nol {\n  margin-bottom: 15px;\n}\ndl {\n  margin-bottom: 30px;\n}\ndt,\ndd {\n  line-height: 1.72222;\n}\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    width: 160px;\n  }\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\nabbr[title],\nabbr[data-original-title] {\n  border-bottom: 1px dotted #bdc3c7;\n}\nblockquote {\n  border-left: 3px solid #e7e9ec;\n  padding: 0 0 0 16px;\n  margin: 0 0 30px;\n}\nblockquote p {\n  font-size: 20px;\n  line-height: 1.55;\n  font-weight: normal;\n  margin-bottom: .4em;\n}\nblockquote small,\nblockquote .small {\n  font-size: 18px;\n  line-height: 1.72222;\n  font-style: italic;\n  color: inherit;\n}\nblockquote small:before,\nblockquote .small:before {\n  content: \"\";\n}\nblockquote.pull-right {\n  padding-right: 16px;\n  padding-left: 0;\n  border-right: 3px solid #e7e9ec;\n  border-left: 0;\n}\nblockquote.pull-right small:after {\n  content: \"\";\n}\naddress {\n  margin-bottom: 30px;\n  line-height: 1.72222;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: Monaco, Menlo, Consolas, \"Courier New\", monospace;\n}\ncode {\n  padding: 2px 6px;\n  font-size: 85%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  border-radius: 4px;\n}\nkbd {\n  padding: 2px 6px;\n  font-size: 85%;\n  color: #ffffff;\n  background-color: #34495e;\n  border-radius: 4px;\n  box-shadow: none;\n}\npre {\n  padding: 8px;\n  margin: 0 0 15px;\n  font-size: 13px;\n  line-height: 1.72222;\n  color: inherit;\n  background-color: #ffffff;\n  border: 2px solid #e7e9ec;\n  border-radius: 6px;\n  white-space: pre;\n}\n.pre-scrollable {\n  max-height: 340px;\n}\n.btn {\n  border: none;\n  font-size: 14px;\n  font-weight: normal;\n  cursor: pointer;\n  line-height: 1.4;\n  border-radius: 4px;\n  padding: 6px 12px;\n  -webkit-font-smoothing: subpixel-antialiased;\n  -webkit-transition: border .25s linear, color .25s linear, background-color .25s linear;\n  transition: border .25s linear, color .25s linear, background-color .25s linear;\n}\n.btn:hover,\n.btn:focus {\n  outline: none;\n  color: #ffffff;\n}\n.btn:active,\n.btn.active {\n  outline: none;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  background-color: #bdc3c7;\n  color: rgba(255, 255, 255, 0.75);\n  opacity: 0.7;\n  filter: alpha(opacity=70);\n}\n.btn > [class^=\"fui-\"] {\n  margin: 0 1px;\n  position: relative;\n  line-height: 1;\n  top: 1px;\n}\n.btn-xs.btn > [class^=\"fui-\"] {\n  font-size: 11px;\n  top: 0;\n}\n.btn-hg.btn > [class^=\"fui-\"] {\n  top: 2px;\n}\n.btn-default {\n  color: #ffffff;\n  background-color: #bdc3c7;\n}\n.btn-default:hover,\n.btn-default:focus,\n.btn-default:active,\n.btn-default.active,\n.open .dropdown-toggle.btn-default {\n  color: #ffffff;\n  background-color: #cacfd2;\n  border-color: #cacfd2;\n}\n.btn-default:active,\n.btn-default.active,\n.open .dropdown-toggle.btn-default {\n  background: #a1a6a9;\n  border-color: #a1a6a9;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #bdc3c7;\n  border-color: #bdc3c7;\n}\n.btn-primary {\n  color: #ffffff;\n  background-color: #428bca;\n}\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary:active,\n.btn-primary.active,\n.open .dropdown-toggle.btn-primary {\n  color: #ffffff;\n  background-color: #3276b1;\n  border-color: #3276b1;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open .dropdown-toggle.btn-primary {\n  background: #428bca;\n  border-color: #428bca;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.btn-info {\n  color: #ffffff;\n  background-color: #3498db;\n}\n.btn-info:hover,\n.btn-info:focus,\n.btn-info:active,\n.btn-info.active,\n.open .dropdown-toggle.btn-info {\n  color: #ffffff;\n  background-color: #5dade2;\n  border-color: #5dade2;\n}\n.btn-info:active,\n.btn-info.active,\n.open .dropdown-toggle.btn-info {\n  background: #2c81ba;\n  border-color: #2c81ba;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #3498db;\n  border-color: #3498db;\n}\n.btn-danger {\n  color: #ffffff;\n  background-color: #e74c3c;\n}\n.btn-danger:hover,\n.btn-danger:focus,\n.btn-danger:active,\n.btn-danger.active,\n.open .dropdown-toggle.btn-danger {\n  color: #ffffff;\n  background-color: #ec7063;\n  border-color: #ec7063;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open .dropdown-toggle.btn-danger {\n  background: #c44133;\n  border-color: #c44133;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #e74c3c;\n  border-color: #e74c3c;\n}\n.btn-success {\n  color: #ffffff;\n  background-color: #2ecc71;\n}\n.btn-success:hover,\n.btn-success:focus,\n.btn-success:active,\n.btn-success.active,\n.open .dropdown-toggle.btn-success {\n  color: #ffffff;\n  background-color: #58d68d;\n  border-color: #58d68d;\n}\n.btn-success:active,\n.btn-success.active,\n.open .dropdown-toggle.btn-success {\n  background: #27ad60;\n  border-color: #27ad60;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #2ecc71;\n  border-color: #2ecc71;\n}\n.btn-warning {\n  color: #ffffff;\n  background-color: #f1c40f;\n}\n.btn-warning:hover,\n.btn-warning:focus,\n.btn-warning:active,\n.btn-warning.active,\n.open .dropdown-toggle.btn-warning {\n  color: #ffffff;\n  background-color: #f4d313;\n  border-color: #f4d313;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open .dropdown-toggle.btn-warning {\n  background: #cda70d;\n  border-color: #cda70d;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #f1c40f;\n  border-color: #f1c40f;\n}\n.btn-inverse {\n  color: #ffffff;\n  background-color: #34495e;\n}\n.btn-inverse:hover,\n.btn-inverse:focus,\n.btn-inverse:active,\n.btn-inverse.active,\n.open .dropdown-toggle.btn-inverse {\n  color: #ffffff;\n  background-color: #415b76;\n  border-color: #415b76;\n}\n.btn-inverse:active,\n.btn-inverse.active,\n.open .dropdown-toggle.btn-inverse {\n  background: #2c3e50;\n  border-color: #2c3e50;\n}\n.btn-inverse.disabled,\n.btn-inverse[disabled],\nfieldset[disabled] .btn-inverse,\n.btn-inverse.disabled:hover,\n.btn-inverse[disabled]:hover,\nfieldset[disabled] .btn-inverse:hover,\n.btn-inverse.disabled:focus,\n.btn-inverse[disabled]:focus,\nfieldset[disabled] .btn-inverse:focus,\n.btn-inverse.disabled:active,\n.btn-inverse[disabled]:active,\nfieldset[disabled] .btn-inverse:active,\n.btn-inverse.disabled.active,\n.btn-inverse[disabled].active,\nfieldset[disabled] .btn-inverse.active {\n  background-color: #34495e;\n  border-color: #34495e;\n}\n.btn-embossed {\n  -webkit-box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.15);\n}\n.btn-embossed.active,\n.btn-embossed:active {\n  -webkit-box-shadow: inset 0 2px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 2px 0 rgba(0, 0, 0, 0.15);\n}\n.btn-wide {\n  min-width: 140px;\n  padding-left: 30px;\n  padding-right: 30px;\n}\n.btn-link {\n  color: #428bca;\n}\n.btn-link:hover,\n.btn-link:focus {\n  color: #428bca;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n  color: #bdc3c7;\n  text-decoration: none;\n}\n.btn-hg {\n  padding: 13px 20px;\n  font-size: 22px;\n  line-height: 1.227;\n  border-radius: 6px;\n}\n.btn-lg {\n  padding: 10px 19px;\n  font-size: 17px;\n  line-height: 1.471;\n  border-radius: 6px;\n}\n.btn-sm {\n  padding: 9px 13px;\n  font-size: 13px;\n  line-height: 1.385;\n  border-radius: 4px;\n}\n.btn-xs {\n  padding: 6px 9px;\n  font-size: 12px;\n  line-height: 1.083;\n  border-radius: 3px;\n}\n.btn-tip {\n  font-weight: 300;\n  padding-left: 10px;\n  font-size: 92%;\n}\n.btn-block {\n  white-space: normal;\n}\n.caret {\n  border-width: 8px 6px;\n  border-bottom-color: #34495e;\n  border-top-color: #34495e;\n  border-style: solid;\n  border-bottom-style: none;\n  -webkit-transition: 0.25s;\n  transition: 0.25s;\n  -webkit-transform: scale(1.001, );\n  -ms-transform: scale(1.001, );\n  transform: scale(1.001, );\n}\n.dropup .caret,\n.dropup .btn-lg .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-bottom-width: 8px;\n}\n.btn-lg .caret {\n  border-top-width: 8px;\n  border-right-width: 6px;\n  border-left-width: 6px;\n}\n.select {\n  display: inline-block;\n  margin-bottom: 10px;\n}\n[class*=\"span\"] > .select[class*=\"span\"] {\n  margin-left: 0;\n}\n.select[class*=\"span\"] .btn {\n  width: 100%;\n}\n.select.select-block {\n  display: block;\n  float: none;\n  margin-left: 0;\n  width: auto;\n}\n.select.select-block:before,\n.select.select-block:after {\n  content: \" \";\n  /* 1 */\n  display: table;\n  /* 2 */\n}\n.select.select-block:after {\n  clear: both;\n}\n.select.select-block .btn {\n  width: 100%;\n}\n.select.select-block .dropdown-menu {\n  width: 100%;\n}\n.select .btn {\n  width: 220px;\n}\n.select .btn.btn-hg .filter-option {\n  left: 20px;\n  right: 40px;\n  top: 13px;\n}\n.select .btn.btn-hg .caret {\n  right: 20px;\n}\n.select .btn.btn-lg .filter-option {\n  left: 18px;\n  right: 38px;\n}\n.select .btn.btn-sm .filter-option {\n  left: 13px;\n  right: 33px;\n}\n.select .btn.btn-sm .caret {\n  right: 13px;\n}\n.select .btn.btn-xs .filter-option {\n  left: 13px;\n  right: 33px;\n  top: 5px;\n}\n.select .btn.btn-xs .caret {\n  right: 13px;\n}\n.select .btn .filter-option {\n  height: 26px;\n  left: 13px;\n  overflow: hidden;\n  position: absolute;\n  right: 33px;\n  text-align: left;\n  top: 10px;\n}\n.select .btn .caret {\n  position: absolute;\n  right: 16px;\n  top: 50%;\n  margin-top: -3px;\n}\n.select .btn .dropdown-toggle {\n  border-radius: 6px;\n}\n.select .btn .dropdown-menu {\n  min-width: 100%;\n}\n.select .btn .dropdown-menu dt {\n  cursor: default;\n  display: block;\n  padding: 3px 20px;\n}\n.select .btn .dropdown-menu li:not(.disabled) > a:hover small {\n  color: rgba(255, 255, 255, 0.004);\n}\n.select .btn .dropdown-menu li > a {\n  min-height: 20px;\n}\n.select .btn .dropdown-menu li > a.opt {\n  padding-left: 35px;\n}\n.select .btn .dropdown-menu li small {\n  padding-left: .5em;\n}\n.select .btn .dropdown-menu li > dt small {\n  font-weight: normal;\n}\n.select .btn > .disabled,\n.select .btn .dropdown-menu li.disabled > a {\n  cursor: default;\n}\n.select .caret {\n  border-bottom-color: #ffffff;\n  border-top-color: #ffffff;\n}\n\ntextarea {\n  font-size: 20px;\n  line-height: 24px;\n  padding: 5px 11px;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: none !important;\n}\nlabel {\n  font-weight: normal;\n  font-size: 15px;\n  line-height: 2.4;\n}\n.form-control:-moz-placeholder {\n  color: #b2bcc5;\n}\n.form-control::-moz-placeholder {\n  color: #b2bcc5;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #b2bcc5;\n}\n.form-control::-webkit-input-placeholder {\n  color: #b2bcc5;\n}\n.form-control.placeholder {\n  color: #b2bcc5;\n}\n.form-control {\n  border: 2px solid #bdc3c7;\n  color: #34495e;\n  font-family: \"Lato\", Helvetica, Arial, sans-serif;\n  font-size: 15px;\n  line-height: 1.467;\n  padding: 8px 12px;\n  height: 42px;\n  -webkit-appearance: none;\n  border-radius: 6px;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n  -webkit-transition: border .25s linear, color .25s linear, background-color .25s linear;\n  transition: border .25s linear, color .25s linear, background-color .25s linear;\n}\n.form-group.focus .form-control,\n.form-control:focus {\n  border-color: #428bca;\n  outline: 0;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  background-color: #f4f6f6;\n  border-color: #d5dbdb;\n  color: #d5dbdb;\n  cursor: default;\n  opacity: 0.7;\n  filter: alpha(opacity=70);\n}\n.form-control.flat {\n  border-color: transparent;\n}\n.form-control.flat:hover {\n  border-color: #bdc3c7;\n}\n.form-control.flat:focus {\n  border-color: #428bca;\n}\n.input-sm {\n  height: 35px;\n  padding: 6px 10px;\n  font-size: 13px;\n  line-height: 1.462;\n  border-radius: 6px;\n}\nselect.input-sm {\n  height: 35px;\n  line-height: 35px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n  height: auto;\n}\n.input-lg {\n  height: 45px;\n  padding: 10px 15px;\n  font-size: 17px;\n  line-height: 1.235;\n  border-radius: 6px;\n}\nselect.input-lg {\n  height: 45px;\n  line-height: 45px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n.input-hg {\n  height: 53px;\n  padding: 10px 16px;\n  font-size: 22px;\n  line-height: 1.318;\n  border-radius: 6px;\n}\nselect.input-hg {\n  height: 53px;\n  line-height: 53px;\n}\ntextarea.input-hg,\nselect[multiple].input-hg {\n  height: auto;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline {\n  color: #f1c40f;\n}\n.has-warning .form-control {\n  color: #f1c40f;\n  border-color: #f1c40f;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.has-warning .form-control:-moz-placeholder {\n  color: #f1c40f;\n}\n.has-warning .form-control::-moz-placeholder {\n  color: #f1c40f;\n  opacity: 1;\n}\n.has-warning .form-control:-ms-input-placeholder {\n  color: #f1c40f;\n}\n.has-warning .form-control::-webkit-input-placeholder {\n  color: #f1c40f;\n}\n.has-warning .form-control.placeholder {\n  color: #f1c40f;\n}\n.has-warning .form-control:focus {\n  border-color: #f1c40f;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.has-warning .input-group-addon {\n  color: #f1c40f;\n  border-color: #f1c40f;\n  background-color: #ffffff;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline {\n  color: #e74c3c;\n}\n.has-error .form-control {\n  color: #e74c3c;\n  border-color: #e74c3c;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.has-error .form-control:-moz-placeholder {\n  color: #e74c3c;\n}\n.has-error .form-control::-moz-placeholder {\n  color: #e74c3c;\n  opacity: 1;\n}\n.has-error .form-control:-ms-input-placeholder {\n  color: #e74c3c;\n}\n.has-error .form-control::-webkit-input-placeholder {\n  color: #e74c3c;\n}\n.has-error .form-control.placeholder {\n  color: #e74c3c;\n}\n.has-error .form-control:focus {\n  border-color: #e74c3c;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.has-error .input-group-addon {\n  color: #e74c3c;\n  border-color: #e74c3c;\n  background-color: #ffffff;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline {\n  color: #2ecc71;\n}\n.has-success .form-control {\n  color: #2ecc71;\n  border-color: #2ecc71;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.has-success .form-control:-moz-placeholder {\n  color: #2ecc71;\n}\n.has-success .form-control::-moz-placeholder {\n  color: #2ecc71;\n  opacity: 1;\n}\n.has-success .form-control:-ms-input-placeholder {\n  color: #2ecc71;\n}\n.has-success .form-control::-webkit-input-placeholder {\n  color: #2ecc71;\n}\n.has-success .form-control.placeholder {\n  color: #2ecc71;\n}\n.has-success .form-control:focus {\n  border-color: #2ecc71;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.has-success .input-group-addon {\n  color: #2ecc71;\n  border-color: #2ecc71;\n  background-color: #ffffff;\n}\n.help-block {\n  font-size: 15px;\n  margin-bottom: 5px;\n  color: inherit;\n}\n.form-group {\n  position: relative;\n  margin-bottom: 20px;\n}\n.form-horizontal .control-label,\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-top: 6px;\n}\n.form-horizontal .form-group {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after {\n  content: \" \";\n  /* 1 */\n  display: table;\n  /* 2 */\n}\n.form-horizontal .form-group:after {\n  clear: both;\n}\n.form-horizontal .form-control-static {\n  padding-top: 6px;\n}\n.form-group {\n  position: relative;\n}\n.form-control + .input-icon {\n  position: absolute;\n  top: 2px;\n  right: 2px;\n  line-height: 37px;\n  vertical-align: middle;\n  font-size: 20px;\n  color: #b2bcc5;\n  background-color: #ffffff;\n  padding: 0 12px 0 0;\n  border-radius: 6px;\n}\n.input-hg + .input-icon {\n  line-height: 49px;\n  padding: 0 16px 0 0;\n}\n.input-lg + .input-icon {\n  line-height: 41px;\n  padding: 0 15px 0 0;\n}\n.input-sm + .input-icon {\n  font-size: 18px;\n  line-height: 30px;\n  padding: 0 10px 0 0;\n}\n.has-success .input-icon {\n  color: #2ecc71;\n}\n.has-warning .input-icon {\n  color: #f1c40f;\n}\n.has-error .input-icon {\n  color: #e74c3c;\n}\n.form-control[disabled] + .input-icon,\n.form-control[readonly] + .input-icon,\nfieldset[disabled] .form-control + .input-icon,\n.form-control.disabled + .input-icon {\n  color: #d5dbdb;\n  background-color: transparent;\n  opacity: 0.7;\n  filter: alpha(opacity=70);\n}\n.input-group-hg > .form-control,\n.input-group-hg > .input-group-addon,\n.input-group-hg > .input-group-btn > .btn {\n  height: 53px;\n  padding: 10px 16px;\n  font-size: 22px;\n  line-height: 1.318;\n  border-radius: 6px;\n}\nselect.input-group-hg > .form-control,\nselect.input-group-hg > .input-group-addon,\nselect.input-group-hg > .input-group-btn > .btn {\n  height: 53px;\n  line-height: 53px;\n}\ntextarea.input-group-hg > .form-control,\ntextarea.input-group-hg > .input-group-addon,\ntextarea.input-group-hg > .input-group-btn > .btn,\nselect[multiple].input-group-hg > .form-control,\nselect[multiple].input-group-hg > .input-group-addon,\nselect[multiple].input-group-hg > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 45px;\n  padding: 10px 15px;\n  font-size: 17px;\n  line-height: 1.235;\n  border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 45px;\n  line-height: 45px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  height: 35px;\n  padding: 6px 10px;\n  font-size: 13px;\n  line-height: 1.462;\n  border-radius: 6px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n  height: 35px;\n  line-height: 35px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-addon {\n  padding: 10px 12px;\n  font-size: 15px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #bdc3c7;\n  border: 1px solid #bdc3c7;\n  border-radius: 6px;\n  -webkit-transition: border .25s linear, color .25s linear, background-color .25s linear;\n  transition: border .25s linear, color .25s linear, background-color .25s linear;\n}\n.input-group-hg .input-group-addon,\n.input-group-lg .input-group-addon,\n.input-group-sm .input-group-addon {\n  line-height: 1;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.form-group.focus .input-group-addon,\n.input-group.focus .input-group-addon {\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.form-group.focus .input-group-btn > .btn-default + .btn-default,\n.input-group.focus .input-group-btn > .btn-default + .btn-default {\n  border-left-color: #428bca;\n}\n.form-group.focus .input-group-btn .btn,\n.input-group.focus .input-group-btn .btn {\n  border-color: #428bca;\n  background-color: #ffffff;\n  color: #428bca;\n}\n.form-group.focus .input-group-btn .btn-default,\n.input-group.focus .input-group-btn .btn-default {\n  color: #ffffff;\n  background-color: #428bca;\n}\n.form-group.focus .input-group-btn .btn-default:hover,\n.input-group.focus .input-group-btn .btn-default:hover,\n.form-group.focus .input-group-btn .btn-default:focus,\n.input-group.focus .input-group-btn .btn-default:focus,\n.form-group.focus .input-group-btn .btn-default:active,\n.input-group.focus .input-group-btn .btn-default:active,\n.form-group.focus .input-group-btn .btn-default.active,\n.input-group.focus .input-group-btn .btn-default.active,\n.open .dropdown-toggle.form-group.focus .input-group-btn .btn-default,\n.open .dropdown-toggle.input-group.focus .input-group-btn .btn-default {\n  color: #ffffff;\n  background-color: #3276b1;\n  border-color: #3276b1;\n}\n.form-group.focus .input-group-btn .btn-default:active,\n.input-group.focus .input-group-btn .btn-default:active,\n.form-group.focus .input-group-btn .btn-default.active,\n.input-group.focus .input-group-btn .btn-default.active,\n.open .dropdown-toggle.form-group.focus .input-group-btn .btn-default,\n.open .dropdown-toggle.input-group.focus .input-group-btn .btn-default {\n  background: #428bca;\n  border-color: #428bca;\n}\n.form-group.focus .input-group-btn .btn-default.disabled,\n.input-group.focus .input-group-btn .btn-default.disabled,\n.form-group.focus .input-group-btn .btn-default[disabled],\n.input-group.focus .input-group-btn .btn-default[disabled],\nfieldset[disabled] .form-group.focus .input-group-btn .btn-default,\nfieldset[disabled] .input-group.focus .input-group-btn .btn-default,\n.form-group.focus .input-group-btn .btn-default.disabled:hover,\n.input-group.focus .input-group-btn .btn-default.disabled:hover,\n.form-group.focus .input-group-btn .btn-default[disabled]:hover,\n.input-group.focus .input-group-btn .btn-default[disabled]:hover,\nfieldset[disabled] .form-group.focus .input-group-btn .btn-default:hover,\nfieldset[disabled] .input-group.focus .input-group-btn .btn-default:hover,\n.form-group.focus .input-group-btn .btn-default.disabled:focus,\n.input-group.focus .input-group-btn .btn-default.disabled:focus,\n.form-group.focus .input-group-btn .btn-default[disabled]:focus,\n.input-group.focus .input-group-btn .btn-default[disabled]:focus,\nfieldset[disabled] .form-group.focus .input-group-btn .btn-default:focus,\nfieldset[disabled] .input-group.focus .input-group-btn .btn-default:focus,\n.form-group.focus .input-group-btn .btn-default.disabled:active,\n.input-group.focus .input-group-btn .btn-default.disabled:active,\n.form-group.focus .input-group-btn .btn-default[disabled]:active,\n.input-group.focus .input-group-btn .btn-default[disabled]:active,\nfieldset[disabled] .form-group.focus .input-group-btn .btn-default:active,\nfieldset[disabled] .input-group.focus .input-group-btn .btn-default:active,\n.form-group.focus .input-group-btn .btn-default.disabled.active,\n.input-group.focus .input-group-btn .btn-default.disabled.active,\n.form-group.focus .input-group-btn .btn-default[disabled].active,\n.input-group.focus .input-group-btn .btn-default[disabled].active,\nfieldset[disabled] .form-group.focus .input-group-btn .btn-default.active,\nfieldset[disabled] .input-group.focus .input-group-btn .btn-default.active {\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.input-group-btn .btn {\n  background-color: #ffffff;\n  border: 2px solid #bdc3c7;\n  color: #bdc3c7;\n  line-height: 18px;\n}\n.input-group-btn .btn-default {\n  color: #ffffff;\n  background-color: #bdc3c7;\n}\n.input-group-btn .btn-default:hover,\n.input-group-btn .btn-default:focus,\n.input-group-btn .btn-default:active,\n.input-group-btn .btn-default.active,\n.open .dropdown-toggle.input-group-btn .btn-default {\n  color: #ffffff;\n  background-color: #cacfd2;\n  border-color: #cacfd2;\n}\n.input-group-btn .btn-default:active,\n.input-group-btn .btn-default.active,\n.open .dropdown-toggle.input-group-btn .btn-default {\n  background: #a1a6a9;\n  border-color: #a1a6a9;\n}\n.input-group-btn .btn-default.disabled,\n.input-group-btn .btn-default[disabled],\nfieldset[disabled] .input-group-btn .btn-default,\n.input-group-btn .btn-default.disabled:hover,\n.input-group-btn .btn-default[disabled]:hover,\nfieldset[disabled] .input-group-btn .btn-default:hover,\n.input-group-btn .btn-default.disabled:focus,\n.input-group-btn .btn-default[disabled]:focus,\nfieldset[disabled] .input-group-btn .btn-default:focus,\n.input-group-btn .btn-default.disabled:active,\n.input-group-btn .btn-default[disabled]:active,\nfieldset[disabled] .input-group-btn .btn-default:active,\n.input-group-btn .btn-default.disabled.active,\n.input-group-btn .btn-default[disabled].active,\nfieldset[disabled] .input-group-btn .btn-default.active {\n  background-color: #bdc3c7;\n  border-color: #bdc3c7;\n}\n.input-group-hg .input-group-btn .btn {\n  line-height: 31px;\n}\n.input-group-lg .input-group-btn .btn {\n  line-height: 21px;\n}\n.input-group-sm .input-group-btn .btn {\n  line-height: 19px;\n}\n.input-group-btn:first-child > .btn {\n  border-right-width: 0;\n  margin-right: -2px;\n}\n.input-group-btn:last-child > .btn {\n  border-left-width: 0;\n  margin-left: -2px;\n}\n.input-group-btn > .btn-default + .btn-default {\n  border-left: 2px solid #bdc3c7;\n}\n.input-group-btn > .btn:first-child + .btn .caret {\n  margin-left: 0;\n}\n.input-group-rounded .input-group-btn + .form-control,\n.input-group-rounded .input-group-btn:last-child .btn {\n  border-bottom-right-radius: 20px;\n  border-top-right-radius: 20px;\n}\n.input-group-hg.input-group-rounded .input-group-btn + .form-control,\n.input-group-hg.input-group-rounded .input-group-btn:last-child .btn {\n  border-bottom-right-radius: 27px;\n  border-top-right-radius: 27px;\n}\n.input-group-lg.input-group-rounded .input-group-btn + .form-control,\n.input-group-lg.input-group-rounded .input-group-btn:last-child .btn {\n  border-bottom-right-radius: 25px;\n  border-top-right-radius: 25px;\n}\n.input-group-rounded .form-control:first-child,\n.input-group-rounded .input-group-btn:first-child .btn {\n  border-bottom-left-radius: 20px;\n  border-top-left-radius: 20px;\n}\n.input-group-hg.input-group-rounded .form-control:first-child,\n.input-group-hg.input-group-rounded .input-group-btn:first-child .btn {\n  border-bottom-left-radius: 27px;\n  border-top-left-radius: 27px;\n}\n.input-group-lg.input-group-rounded .form-control:first-child,\n.input-group-lg.input-group-rounded .input-group-btn:first-child .btn {\n  border-bottom-left-radius: 25px;\n  border-top-left-radius: 25px;\n}\n.input-group-rounded .input-group-btn + .form-control {\n  padding-left: 0;\n}\n.checkbox,\n.radio {\n  margin-bottom: 12px;\n  padding-left: 32px;\n  position: relative;\n  -webkit-transition: color 0.25s linear;\n  transition: color 0.25s linear;\n  font-size: 14px;\n  line-height: 1.5;\n}\n.checkbox input,\n.radio input {\n  outline: none !important;\n  display: none;\n}\n.checkbox .icons,\n.radio .icons {\n  color: #bdc3c7;\n  display: block;\n  height: 20px;\n  left: 0;\n  position: absolute;\n  top: 0;\n  width: 20px;\n  text-align: center;\n  line-height: 21px;\n  font-size: 20px;\n  cursor: pointer;\n  -webkit-transition: color 0.25s linear;\n  transition: color 0.25s linear;\n}\n.checkbox .icons .first-icon,\n.radio .icons .first-icon,\n.checkbox .icons .second-icon,\n.radio .icons .second-icon {\n  display: inline-table;\n  position: absolute;\n  left: 0;\n  top: 0;\n  background-color: transparent;\n  margin: 0;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.checkbox .icons .second-icon,\n.radio .icons .second-icon {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.checkbox:hover,\n.radio:hover {\n  -webkit-transition: color 0.25s linear;\n  transition: color 0.25s linear;\n}\n.checkbox:hover .first-icon,\n.radio:hover .first-icon {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.checkbox:hover .second-icon,\n.radio:hover .second-icon {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.checkbox.checked,\n.radio.checked {\n  color: #428bca;\n}\n.checkbox.checked .first-icon,\n.radio.checked .first-icon {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.checkbox.checked .second-icon,\n.radio.checked .second-icon {\n  opacity: 1;\n  filter: alpha(opacity=100);\n  color: #428bca;\n  -webkit-transition: color 0.25s linear;\n  transition: color 0.25s linear;\n}\n.checkbox.disabled,\n.radio.disabled {\n  cursor: default;\n  color: #e6e8ea;\n}\n.checkbox.disabled .icons,\n.radio.disabled .icons {\n  color: #e6e8ea;\n}\n.checkbox.disabled .first-icon,\n.radio.disabled .first-icon {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.checkbox.disabled .second-icon,\n.radio.disabled .second-icon {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.checkbox.disabled.checked .icons,\n.radio.disabled.checked .icons {\n  color: #e6e8ea;\n}\n.checkbox.disabled.checked .first-icon,\n.radio.disabled.checked .first-icon {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.checkbox.disabled.checked .second-icon,\n.radio.disabled.checked .second-icon {\n  opacity: 1;\n  filter: alpha(opacity=100);\n  color: #e6e8ea;\n}\n.checkbox.primary .icons,\n.radio.primary .icons {\n  color: #34495e;\n}\n.checkbox.primary.checked,\n.radio.primary.checked {\n  color: #428bca;\n}\n.checkbox.primary.checked .icons,\n.radio.primary.checked .icons {\n  color: #428bca;\n}\n.checkbox.primary.disabled,\n.radio.primary.disabled {\n  cursor: default;\n  color: #bdc3c7;\n}\n.checkbox.primary.disabled .icons,\n.radio.primary.disabled .icons {\n  color: #bdc3c7;\n}\n.checkbox.primary.disabled.checked .icons,\n.radio.primary.disabled.checked .icons {\n  color: #bdc3c7;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: 10px;\n}\n.tooltip {\n  font-size: 14px;\n  line-height: 1.286;\n}\n.tooltip.in {\n  opacity: 1;\n}\n.tooltip.top {\n  padding-bottom: 9px;\n}\n.tooltip.top .tooltip-arrow {\n  border-top-color: #34495e;\n  border-width: 9px 9px 0;\n  bottom: 0;\n  margin-left: -9px;\n}\n.tooltip.right .tooltip-arrow {\n  border-right-color: #34495e;\n  border-width: 9px 9px 9px 0;\n  margin-top: -9px;\n  left: -3px;\n}\n.tooltip.bottom {\n  padding-top: 8px;\n}\n.tooltip.bottom .tooltip-arrow {\n  border-bottom-color: #34495e;\n  border-width: 0 9px 9px;\n  margin-left: -9px;\n  top: -1px;\n}\n.tooltip.left .tooltip-arrow {\n  border-left-color: #34495e;\n  border-width: 9px 0 9px 9px;\n  margin-top: -9px;\n  right: -3px;\n}\n.tooltip-inner {\n  background-color: #34495e;\n  line-height: 1.286;\n  padding: 12px 12px;\n  text-align: center;\n  width: 183px;\n  border-radius: 6px;\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (-moz-min-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 2) {\n  .login {\n    background-image: url(../images/login/imac-2x.png);\n  }\n}\n"
  },
  {
    "path": "res/css/style.css",
    "content": "@CHARSET \"UTF-8\";\n.clear {\n  clear: both;\n}\nhtml,body{margin: 0;padding: 0}\n#nav {\n  filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=90);\n  opacity: 0.9;\n  background: #FFF;\n  padding: 0;\n  margin:0;\n  background: #446CB3;\n  color:white;\n}\n#menu{  width: 80%;\n  margin: 0 auto\n }\n#nav ul {\n  margin: 0px auto;\n  padding: 0px;\n  list-style-type: none;\n}\n#nav ul li {\n  float: left;\n  padding: 10px 10px;\n  font-size: 14px;\n  border-right: 1px solid rgba(0, 0, 0, 0.1);\n  box-shadow: 1px 0 0 rgba(255, 255, 255, 0.11);\n  font-weight: bold;\n  text-align: center;\n}\n.border_first{\n  border-left: 1px solid rgba(0, 0, 0, 0.1);\n  box-shadow: 1px 0 0 rgba(255, 255, 255, 0.11);\n}\n\n#nav ul#left_submenu li:HOVER{\n\tbackground: white;\n}\n#nav ul#left_submenu li:HOVER a{\n\tcolor:#446CB3\n}\n#nav ul li a{display: inline-block;width:50px; color:white;}\n\n#network-tb td{\n    vertical-align: top\n}\n\n#aside {\n    width:33%;\n    min-width: 450px;\n}\n.w120{width: 120px}\n.w140{width: 140px}\n.w150{width: 150px}\n\n#connect_status{padding:6px;color: white}\n\ntable {border-collapse: collapse;border-spacing: 0;}\n.tb_1{border:1px solid #cccccc;table-layout:fixed;word-break:break-all;width: 100%;background:#ffffff;margin-bottom:5px}\n.tb_1 caption{text-align: center;background: #F0F4F6;font-weight: bold;padding-top: 5px;height: 25px;border:1px solid #cccccc;border-bottom:none}\n.tb_1 a{margin:0 3px 0 3px}\n.tb_1 tr th,.tb_1 tr td{padding: 3px;border:1px solid #cccccc;line-height:20px}\n.tb_1 thead tr th{font-weight:bold;text-align: center;background:#e3eaee}\n.tb_1 tbody tr th{text-align: right;background:#f0f4f6;padding-right:5px}\n.tb_1 tfoot{color:#cccccc}\n.td_c td{text-align: center}\n.td_r td{text-align: right}\n.t_c{text-align: center !important;}\n.t_r{text-align: right !important;}\n.t_l{text-align: left !important;}\n\n.panel_1{background: #e5e2eb;padding:4px}\n#network_filter_form fieldset{padding-right:3px}\n\n #tb_network{font-size: 11px;margin-top: -8px;}\n #tb_network td{overflow: auto;cursor: pointer;}\n#right_content{margin-top:5px}\n #right_content table th,#right_content table td{font-size:11px;vertical-align: top}\n #right_content pre{border:none}\n \n #div_tb_network_list {overflow:auto;max-height: 1000px;min-height:450px}\n tr.selected{background: #ccffee;}\n .right{float: right}\n .left{float:left}\n .c{clear: both}\n .hide{display:none}\n#network_list_div tbody th{text-align: right;}\n.td_ul{list-style: none inside;padding: 0;margin: 0}\n.td_ul li{list-style: none inside;}\n\ntd.td_has_sub{padding: 0 !important;}\ntd.td_has_sub .tb_1{margin: 0;border: 0;}\n\n#bd0{margin:0 auto;width:80%}\n.form-control{height: 26px;padding:0}\nfieldset {\n\tborder-radius:10px;\n\tborder: 1px solid gray\n}\ntr.replay{\n\tcolor:blue;\n}\n\n.res_td_body{\n\tmax-height: 120px;\n\toverflow: scroll;\n}\n\n.div_b_i{\n\tdisplay: inline-block;\n}\n\n.login-screen {\n  min-height: 400px;\n  width:300px;\n  margin: 0 auto;\n  text-align: center;\n}\n\n#bd{\n\tmargin: 0 auto;\n\twidth:80%;\n\tpadding-top: 30px;\n}\n\n.form_0 table{width: 100%}\n.form_0 th{text-align: right;width: 180px;vertical-align:top;}\n.form_0 input[type=text]{width: 100%;margin-bottom:2px}\n.form_0 td.last{width: 90px;padding-left: 10px}\n.oneline{height: 20px;overflow: hidden;}\n\nimg {margin-bottom: -3px}"
  },
  {
    "path": "res/js/base64.js",
    "content": "/**\n*\n*  Base64 encode / decode\n*  http://www.webtoolkit.info/\n*\n**/\nvar Base64 = {\n\n// private property\n_keyStr : \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",\n\n// public method for encoding\nencode : function (input) {\n    var output = \"\";\n    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;\n    var i = 0;\n\n    input = Base64._utf8_encode(input);\n\n    while (i < input.length) {\n\n        chr1 = input.charCodeAt(i++);\n        chr2 = input.charCodeAt(i++);\n        chr3 = input.charCodeAt(i++);\n\n        enc1 = chr1 >> 2;\n        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n        enc4 = chr3 & 63;\n\n        if (isNaN(chr2)) {\n            enc3 = enc4 = 64;\n        } else if (isNaN(chr3)) {\n            enc4 = 64;\n        }\n\n        output = output +\n        this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +\n        this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);\n\n    }\n\n    return output;\n},\n\n// public method for decoding\ndecode : function (input) {\n    var output = \"\";\n    var chr1, chr2, chr3;\n    var enc1, enc2, enc3, enc4;\n    var i = 0;\n\n    input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n    while (i < input.length) {\n\n        enc1 = this._keyStr.indexOf(input.charAt(i++));\n        enc2 = this._keyStr.indexOf(input.charAt(i++));\n        enc3 = this._keyStr.indexOf(input.charAt(i++));\n        enc4 = this._keyStr.indexOf(input.charAt(i++));\n\n        chr1 = (enc1 << 2) | (enc2 >> 4);\n        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n        chr3 = ((enc3 & 3) << 6) | enc4;\n\n        output = output + String.fromCharCode(chr1);\n\n        if (enc3 != 64) {\n            output = output + String.fromCharCode(chr2);\n        }\n        if (enc4 != 64) {\n            output = output + String.fromCharCode(chr3);\n        }\n\n    }\n\n    output = Base64._utf8_decode(output);\n\n    return output;\n\n},\n\n// private method for UTF-8 encoding\n_utf8_encode : function (string) {\n    string = string.replace(/\\r\\n/g,\"\\n\");\n    var utftext = \"\";\n\n    for (var n = 0; n < string.length; n++) {\n\n        var c = string.charCodeAt(n);\n\n        if (c < 128) {\n            utftext += String.fromCharCode(c);\n        }\n        else if((c > 127) && (c < 2048)) {\n            utftext += String.fromCharCode((c >> 6) | 192);\n            utftext += String.fromCharCode((c & 63) | 128);\n        }\n        else {\n            utftext += String.fromCharCode((c >> 12) | 224);\n            utftext += String.fromCharCode(((c >> 6) & 63) | 128);\n            utftext += String.fromCharCode((c & 63) | 128);\n        }\n\n    }\n\n    return utftext;\n},\n\n// private method for UTF-8 decoding\n_utf8_decode : function (utftext) {\n    var string = \"\";\n    var i = 0;\n    var c = c1 = c2 = 0;\n\n    while ( i < utftext.length ) {\n\n        c = utftext.charCodeAt(i);\n\n        if (c < 128) {\n            string += String.fromCharCode(c);\n            i++;\n        }\n        else if((c > 191) && (c < 224)) {\n            c2 = utftext.charCodeAt(i+1);\n            string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));\n            i += 2;\n        }\n        else {\n            c2 = utftext.charCodeAt(i+1);\n            c3 = utftext.charCodeAt(i+2);\n            string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));\n            i += 3;\n        }\n\n    }\n\n    return string;\n}\n\n}"
  },
  {
    "path": "res/js/default.js",
    "content": "function pproxy_tab_sup(target){\n\t$(target).find(\"textarea\").bind('keydown', function(e) {\n\t    if (e.keyCode == 9 ) {\n\t        e.preventDefault();\n\t        this.setRangeText('\\t');\n\t        this.selectionEnd = ++this.selectionStart;\n\t    }\n\t});\n}"
  },
  {
    "path": "res/js/jquery.js",
    "content": "/*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */\n(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f(\"<\"+a+\">\").appendTo(b),e=d.css(\"display\");d.remove();if(e===\"none\"||e===\"\"){ch||(ch=c.createElement(\"iframe\"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode===\"CSS1Compat\"?\"<!doctype html>\":\"\")+\"<html><body>\"),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,\"display\"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h==\"string\"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k===\"*\")k=l;else if(l!==\"*\"&&l!==k){m=l+\" \"+k,n=e[m]||e[\"* \"+k];if(!n){p=b;for(o in e){j=o.split(\" \");if(j[0]===l||j[0]===\"*\"){p=e[j[1]+\" \"+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error(\"No conversion from \"+m.replace(\" \",\" to \")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bZ(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]===\"*\")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader(\"content-type\"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+\" \"+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bY(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bA.test(a)?d(a,e):bY(a+\"[\"+(typeof e==\"object\"||f.isArray(e)?b:\"\")+\"]\",e,c,d)});else if(!c&&b!=null&&typeof b==\"object\")for(var e in b)bY(a+\"[\"+e+\"]\",b[e],c,d);else d(a,b)}function bX(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bW(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bP,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l==\"string\"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bW(a,c,d,e,l,g)));(k||!l)&&!g[\"*\"]&&(l=bW(a,c,d,e,\"*\",g));return l}function bV(a){return function(b,c){typeof b!=\"string\"&&(c=b,b=\"*\");if(f.isFunction(c)){var d=b.toLowerCase().split(bL),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\\+/.test(h),j&&(h=h.substr(1)||\"*\"),i=a[h]=a[h]||[],i[j?\"unshift\":\"push\"](c)}}}function by(a,b,c){var d=b===\"width\"?a.offsetWidth:a.offsetHeight,e=b===\"width\"?bt:bu;if(d>0){c!==\"border\"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,\"padding\"+this))||0),c===\"margin\"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,\"border\"+this+\"Width\"))||0});return d+\"px\"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,\"padding\"+this))||0,c!==\"padding\"&&(d+=parseFloat(f.css(a,\"border\"+this+\"Width\"))||0),c===\"margin\"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+\"px\"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:\"script\"}):f.globalEval((b.text||b.textContent||b.innerHTML||\"\").replace(bd,\"/*$0*/\")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,\"input\")?bj(a):\"getElementsByTagName\"in a&&f.grep(a.getElementsByTagName(\"input\"),bj)}function bj(a){if(a.type===\"checkbox\"||a.type===\"radio\")a.defaultChecked=a.checked}function bi(a){return\"getElementsByTagName\"in a?a.getElementsByTagName(\"*\"):\"querySelectorAll\"in a?a.querySelectorAll(\"*\"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c===\"object\")b.outerHTML=a.outerHTML;else if(c!==\"input\"||a.type!==\"checkbox\"&&a.type!==\"radio\"){if(c===\"option\")b.selected=a.defaultSelected;else if(c===\"input\"||c===\"textarea\")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)f.event.add(b,h+(g[h][i].namespace?\".\":\"\")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function bf(a,b){return f.nodeName(a,\"table\")?a.getElementsByTagName(\"tbody\")[0]||a.appendChild(a.ownerDocument.createElement(\"tbody\")):a}function V(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b==\"string\"){var d=f.grep(a,function(a){return a.nodeType===1});if(Q.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!==\"*\"?a+\".\":\"\")+b.replace(y,\"`\").replace(z,\"&\")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,\"events\");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type===\"click\")){a.namespace&&(n=new RegExp(\"(^|\\\\.)\"+a.namespace.split(\".\").join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\")),a.liveFired=this;var s=r.live.slice(0);for(i=0;i<s.length;i++)g=s[i],g.origType.replace(w,\"\")===a.type?q.push(g.selector):s.splice(i--,1);e=f(a.target).closest(q,a.currentTarget);for(j=0,k=e.length;j<k;j++){m=e[j];for(i=0;i<s.length;i++){g=s[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,d=null;if(g.preType===\"mouseenter\"||g.preType===\"mouseleave\")a.type=g.preType,d=f(a.relatedTarget).closest(g.selector)[0],d&&f.contains(h,d)&&(d=h);(!d||d!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){e=p[j];if(c&&e.level>c)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+\"defer\",g=c+\"queue\",h=c+\"mark\",i=f.data(a,e,b,!0);i&&(d===\"queue\"||!f.data(a,g,b,!0))&&(d===\"mark\"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!==\"toJSON\")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e=\"data-\"+c.replace(j,\"-$1\").toLowerCase();d=a.getAttribute(e);if(typeof d==\"string\"){try{d=d===\"true\"?!0:d===\"false\"?!1:d===\"null\"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll(\"left\")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]*)$)/,j=/\\S/,k=/^\\s+/,l=/\\s+$/,m=/\\d/,n=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,o=/^[\\],:{}\\s]*$/,p=/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,r=/(?:^|:|,)(?:\\s*\\[)+/g,s=/(webkit)[ \\/]([\\w.]+)/,t=/(opera)(?:.*version)?[ \\/]([\\w.]+)/,u=/(msie) ([\\w.]+)/,v=/(mozilla)(?:.*? rv:([\\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+\"\").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a===\"body\"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a==\"string\"){a.charAt(0)!==\"<\"||a.charAt(a.length-1)!==\">\"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:\"\",jquery:\"1.6.4\",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b===\"find\"?d.selector=this.selector+(this.selector?\" \":\"\")+c:b&&(d.selector=this.selector+\".\"+b+\"(\"+c+\")\");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),\"slice\",G.call(arguments).join(\",\"))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==\"boolean\"&&(l=i,i=arguments[1]||{},j=2),typeof i!=\"object\"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger(\"ready\").unbind(\"ready\")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState===\"complete\")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener(\"DOMContentLoaded\",C,!1),a.addEventListener(\"load\",e.ready,!1);else if(c.attachEvent){c.attachEvent(\"onreadystatechange\",C),a.attachEvent(\"onload\",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)===\"function\"},isArray:Array.isArray||function(a){return e.type(a)===\"array\"},isWindow:function(a){return a&&typeof a==\"object\"&&\"setInterval\"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||\"object\"},isPlainObject:function(a){if(!a||e.type(a)!==\"object\"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,\"constructor\")&&!E.call(a.constructor.prototype,\"isPrototypeOf\"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=\"string\"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,\"@\").replace(q,\"]\").replace(r,\"\")))return(new Function(\"return \"+b))();e.error(\"Invalid JSON: \"+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,\"text/xml\")):(d=new ActiveXObject(\"Microsoft.XMLDOM\"),d.async=\"false\",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName(\"parsererror\").length)&&e.error(\"Invalid XML: \"+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,\"ms-\").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:H?function(a){return a==null?\"\":H.call(a)}:function(a){return a==null?\"\":(a+\"\").replace(k,\"\").replace(l,\"\")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d===\"string\"||d===\"function\"||d===\"regexp\"||e.isWindow(a)?F.call(c,a):e.merge(c,a)}return c},inArray:function(a,b){if(!b)return-1;if(I)return I.call(b,a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length==\"number\")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j==\"number\"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c==\"string\"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=G.call(arguments,2),g=function(){return a.apply(c,f.concat(G.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c==\"object\"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=s.exec(a)||t.exec(a)||u.exec(a)||a.indexOf(\"compatible\")<0&&v.exec(a)||[];return{browser:b[1]||\"\",version:b[2]||\"0\"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each(\"Boolean Number String Function Array Date RegExp Object\".split(\" \"),function(a,b){J[\"[object \"+b+\"]\"]=b.toLowerCase()}),A=e.uaMatch(z),A.browser&&(e.browser[A.browser]=!0,e.browser.version=A.version),e.browser.webkit&&(e.browser.safari=!0),j.test(\" \")&&(k=/^[\\s\\xA0]+/,l=/[\\s\\xA0]+$/),h=e(c),c.addEventListener?C=function(){c.removeEventListener(\"DOMContentLoaded\",C,!1),e.ready()}:c.attachEvent&&(C=function(){c.readyState===\"complete\"&&(c.detachEvent(\"onreadystatechange\",C),e.ready())});return e}(),g=\"done fail isResolved isRejected promise then always pipe\".split(\" \"),h=[].slice;f.extend({_Deferred:function(){var a=[],b,c,d,e={done:function(){if(!d){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=f.type(i),j===\"array\"?e.done.apply(e,i):j===\"function\"&&a.push(i);k&&e.resolveWith(k[0],k[1])}return this},resolveWith:function(e,f){if(!d&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(e,f)}finally{b=[e,f],c=0}}return this},resolve:function(){e.resolveWith(this,arguments);return this},isResolved:function(){return!!c||!!b},cancel:function(){d=1,a=[];return this}};return e},Deferred:function(a){var b=f._Deferred(),c=f._Deferred(),d;f.extend(b,{then:function(a,c){b.done(a).fail(c);return this},always:function(){return b.done.apply(b,arguments).fail.apply(this,arguments)},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,pipe:function(a,c){return f.Deferred(function(d){f.each({done:[a,\"resolve\"],fail:[c,\"reject\"]},function(a,c){var e=c[0],g=c[1],h;f.isFunction(e)?b[a](function(){h=e.apply(this,arguments),h&&f.isFunction(h.promise)?h.promise().then(d.resolve,d.reject):d[g+\"With\"](this===b?d:this,[h])}):b[a](d[g])})}).promise()},promise:function(a){if(a==null){if(d)return d;d=a={}}var c=g.length;while(c--)a[g[c]]=b[g[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c<d;c++)b[c]&&f.isFunction(b[c].promise)?b[c].promise().then(i(c),g.reject):--e;e||g.resolveWith(g,b)}else g!==a&&g.resolveWith(g,d?[a]:[]);return g.promise()}}),f.support=function(){var a=c.createElement(\"div\"),b=c.documentElement,d,e,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u;a.setAttribute(\"className\",\"t\"),a.innerHTML=\"   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>\",d=a.getElementsByTagName(\"*\"),e=a.getElementsByTagName(\"a\")[0];if(!d||!d.length||!e)return{};g=c.createElement(\"select\"),h=g.appendChild(c.createElement(\"option\")),i=a.getElementsByTagName(\"input\")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName(\"tbody\").length,htmlSerialize:!!a.getElementsByTagName(\"link\").length,style:/top/.test(e.getAttribute(\"style\")),hrefNormalized:e.getAttribute(\"href\")===\"/a\",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value===\"on\",optSelected:h.selected,getSetAttribute:a.className!==\"t\",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent(\"onclick\",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent(\"onclick\")),i=c.createElement(\"input\"),i.value=\"t\",i.setAttribute(\"type\",\"radio\"),k.radioValue=i.value===\"t\",i.setAttribute(\"checked\",\"checked\"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML=\"\",a.style.width=a.style.paddingLeft=\"1px\",m=c.getElementsByTagName(\"body\")[0],o=c.createElement(m?\"div\":\"body\"),p={visibility:\"hidden\",width:0,height:0,border:0,margin:0,background:\"none\"},m&&f.extend(p,{position:\"absolute\",left:\"-1000px\",top:\"-1000px\"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,\"zoom\"in a.style&&(a.style.display=\"inline\",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display=\"\",a.innerHTML=\"<div style='width:4px;'></div>\",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML=\"<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>\",q=a.getElementsByTagName(\"td\"),u=q[0].offsetHeight===0,q[0].style.display=\"\",q[1].style.display=\"none\",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML=\"\",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement(\"div\"),j.style.width=\"0\",j.style.marginRight=\"0\",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML=\"\",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s=\"on\"+t,u=s in a,u||(a.setAttribute(s,\"return;\"),u=typeof a[s]==\"function\"),k[t+\"Bubbles\"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\\{.*\\}|\\[.*\\])$/,j=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:\"jQuery\"+(f.fn.jquery+Math.random()).replace(/\\D/g,\"\"),noData:{embed:!0,object:\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c==\"string\",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c==\"object\"||typeof c==\"function\")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c===\"events\"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute(\"classid\")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a==\"undefined\"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h<i;h++)g=e[h].name,g.indexOf(\"data-\")===0&&(g=f.camelCase(g.substring(5)),k(this[0],g,d[g]))}}return d}if(typeof a==\"object\")return this.each(function(){f.data(this,a)});var j=a.split(\".\");j[1]=j[1]?\".\"+j[1]:\"\";if(c===b){d=this.triggerHandler(\"getData\"+j[1]+\"!\",[j[0]]),d===b&&this.length&&(d=f.data(this[0],a),d=k(this[0],a,d));return d===b&&j[1]?this.data(j[0]):d}return this.each(function(){var b=f(this),d=[j[0],c];b.triggerHandler(\"setData\"+j[1]+\"!\",d),f.data(this,a,c),b.triggerHandler(\"changeData\"+j[1]+\"!\",d)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,c){a&&(c=(c||\"fx\")+\"mark\",f.data(a,c,(f.data(a,c,b,!0)||0)+1,!0))},_unmark:function(a,c,d){a!==!0&&(d=c,c=a,a=!1);if(c){d=d||\"fx\";var e=d+\"mark\",g=a?0:(f.data(c,e,b,!0)||1)-1;g?f.data(c,e,g,!0):(f.removeData(c,e,!0),m(c,d,\"mark\"))}},queue:function(a,c,d){if(a){c=(c||\"fx\")+\"queue\";var e=f.data(a,c,b,!0);d&&(!e||f.isArray(d)?e=f.data(a,c,f.makeArray(d),!0):e.push(d));return e||[]}},dequeue:function(a,b){b=b||\"fx\";var c=f.queue(a,b),d=c.shift(),e;d===\"inprogress\"&&(d=c.shift()),d&&(b===\"fx\"&&c.unshift(\"inprogress\"),d.call(a,function(){f.dequeue(a,b)})),c.length||(f.removeData(a,b+\"queue\",!0),m(a,b,\"queue\"))}}),f.fn.extend({queue:function(a,c){typeof a!=\"string\"&&(c=a,a=\"fx\");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a===\"fx\"&&b[0]!==\"inprogress\"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||\"fx\";return this.queue(b,function(){var c=this;setTimeout(function(){f.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||\"fx\",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!=\"string\"&&(c=a,a=b),a=a||\"fx\";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+\"defer\",j=a+\"queue\",k=a+\"mark\",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f._Deferred(),!0))h++,l.done(m);m();return d.promise()}});var n=/[\\n\\t\\r]/g,o=/\\s+/,p=/\\r/g,q=/^(?:button|input)$/i,r=/^(?:button|input|object|select|textarea)$/i,s=/^a(?:rea)?$/i,t=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,u,v;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a==\"string\"){b=a.split(o);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=\" \"+e.className+\" \";for(h=0,i=b.length;h<i;h++)~g.indexOf(\" \"+b[h]+\" \")||(g+=b[h]+\" \");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a==\"string\"||a===b){c=(a||\"\").split(o);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(\" \"+g.className+\" \").replace(n,\" \");for(i=0,j=c.length;i<j;i++)h=h.replace(\" \"+c[i]+\" \",\" \");g.className=f.trim(h)}else g.className=\"\"}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b==\"boolean\";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c===\"string\"){var e,g=0,h=f(this),i=b,j=a.split(o);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?\"addClass\":\"removeClass\"](e)}else if(c===\"undefined\"||c===\"boolean\")this.className&&f._data(this,\"__className__\",this.className),this.className=this.className||a===!1?\"\":f._data(this,\"__className__\")||\"\"})},hasClass:function(a){var b=\" \"+a+\" \";for(var c=0,d=this.length;c<d;c++)if(this[c].nodeType===1&&(\" \"+this[c].className+\" \").replace(n,\" \").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&\"get\"in c&&(d=c.get(e,\"value\"))!==b)return d;d=e.value;return typeof d==\"string\"?d.replace(p,\"\"):d==null?\"\":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h=\"\":typeof h==\"number\"?h+=\"\":f.isArray(h)&&(h=f.map(h,function(a){return a==null?\"\":a+\"\"})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!(\"set\"in c)||c.set(this,h,\"value\")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type===\"select-one\";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h<i;h++){var j=e[h];if(j.selected&&(f.support.optDisabled?!j.disabled:j.getAttribute(\"disabled\")===null)&&(!j.parentNode.disabled||!f.nodeName(j.parentNode,\"optgroup\"))){b=f(j).val();if(g)return b;d.push(b)}}if(g&&!d.length&&e.length)return f(e[c]).val();return d},set:function(a,b){var c=f.makeArray(b);f(a).find(\"option\").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:\"tabIndex\"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!(\"getAttribute\"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&\"set\"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,\"\"+d);return d}if(i&&\"get\"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,\"\"),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error(\"type property can't be changed\");else if(!f.support.radioValue&&b===\"radio\"&&f.nodeName(a,\"input\")){var c=a.value;a.setAttribute(\"type\",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,\"button\"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,\"button\"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:\"tabIndex\",readonly:\"readOnly\",\"for\":\"htmlFor\",\"class\":\"className\",maxlength:\"maxLength\",cellspacing:\"cellSpacing\",cellpadding:\"cellPadding\",rowspan:\"rowSpan\",colspan:\"colSpan\",usemap:\"useMap\",frameborder:\"frameBorder\",contenteditable:\"contentEditable\"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&\"set\"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&\"get\"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode(\"tabindex\");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==\"\"?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+\"\"}},f.each([\"width\",\"height\"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===\"\"){a.setAttribute(b,\"auto\");return c}}})})),f.support.hrefNormalized||f.each([\"href\",\"src\",\"width\",\"height\"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=\"\"+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each([\"radio\",\"checkbox\"],function(){f.valHooks[this]={get:function(a){return a.getAttribute(\"value\")===null?\"on\":a.value}}}),f.each([\"radio\",\"checkbox\"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\\./g,z=/ /g,A=/[^\\w\\s.|`]/g,B=function(a){return a.replace(A,\"\\\\$&\")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!=\"undefined\"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(\" \");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(\".\")>-1?(n=l.split(\".\"),l=n.shift(),h.namespace=n.slice(0).sort().join(\".\")):(n=[],h.namespace=\"\"),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent(\"on\"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c==\"string\"&&c.charAt(0)===\".\"){c=c||\"\";for(h in t)f.event.remove(a,h+c);return}c=c.split(\" \");while(h=c[k++]){r=h,q=null,l=h.indexOf(\".\")<0,m=[],l||(m=h.split(\".\"),h=m.shift(),n=new RegExp(\"(^|\\\\.)\"+f.map(m.slice(0).sort(),B).join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\")),p=t[h];if(!p)continue;if(!d){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))f.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=f.event.special[h]||{};for(j=e||0;j<p.length;j++){q=p[j];if(d.guid===q.guid){if(l||n.test(q.namespace))e==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(e!=null)break}}if(p.length===0||e!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&f.removeEvent(a,h,s.handle),g=null,delete \nt[h]}if(f.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,f.isEmptyObject(s)&&f.removeData(a,b,!0)}}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){var h=c.type||c,i=[],j;h.indexOf(\"!\")>=0&&(h=h.slice(0,-1),j=!0),h.indexOf(\".\")>=0&&(i=h.split(\".\"),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c==\"object\"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join(\".\"),c.namespace_re=new RegExp(\"(^|\\\\.)\"+i.join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(\":\")<0?\"on\"+h:\"\";do{var m=f._data(k,\"handle\");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!==\"click\"||!f.nodeName(e,\"a\"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,\"events\")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h<i;h++){var j=d[h];if(e||c.namespace_re.test(j.namespace)){c.handler=j.handler,c.data=j.data,c.handleObj=j;var k=j.handler.apply(this,g);k!==b&&(c.result=k,k===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}return c.result},props:\"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which\".split(\" \"),fix:function(a){if(a[f.expando])return a;var d=a;a=f.Event(d);for(var e=this.props.length,g;e;)g=this.props[--e],a[g]=d[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=a.target.ownerDocument||c,i=h.documentElement,j=h.body;a.pageX=a.clientX+(i&&i.scrollLeft||j&&j.scrollLeft||0)-(i&&i.clientLeft||j&&j.clientLeft||0),a.pageY=a.clientY+(i&&i.scrollTop||j&&j.scrollTop||0)-(i&&i.clientTop||j&&j.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:f.proxy,special:{ready:{setup:f.bindReady,teardown:f.noop},live:{add:function(a){f.event.add(this,M(a.origType,a.selector),f.extend({},a,{handler:L,guid:a.handler.guid}))},remove:function(a){f.event.remove(this,M(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent(\"on\"+b,c)},f.Event=function(a,b){if(!this.preventDefault)return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?D:C):this.type=a,b&&f.extend(this,b),this.timeStamp=f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=D;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=D;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=D,this.stopPropagation()},isDefaultPrevented:C,isPropagationStopped:C,isImmediatePropagationStopped:C};var E=function(a){var b=a.relatedTarget,c=!1,d=a.type;a.type=a.data,b!==this&&(b&&(c=f.contains(this,b)),c||(f.event.handle.apply(this,arguments),a.type=d))},F=function(a){a.type=a.data,f.event.handle.apply(this,arguments)};f.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\"},function(a,b){f.event.special[a]={setup:function(c){f.event.add(this,b,c&&c.selector?F:E,a)},teardown:function(a){f.event.remove(this,b,a&&a.selector?F:E)}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(a,b){if(!f.nodeName(this,\"form\"))f.event.add(this,\"click.specialSubmit\",function(a){var b=a.target,c=f.nodeName(b,\"input\")||f.nodeName(b,\"button\")?b.type:\"\";(c===\"submit\"||c===\"image\")&&f(b).closest(\"form\").length&&J(\"submit\",this,arguments)}),f.event.add(this,\"keypress.specialSubmit\",function(a){var b=a.target,c=f.nodeName(b,\"input\")||f.nodeName(b,\"button\")?b.type:\"\";(c===\"text\"||c===\"password\")&&f(b).closest(\"form\").length&&a.keyCode===13&&J(\"submit\",this,arguments)});else return!1},teardown:function(a){f.event.remove(this,\".specialSubmit\")}});if(!f.support.changeBubbles){var G,H=function(a){var b=f.nodeName(a,\"input\")?a.type:\"\",c=a.value;b===\"radio\"||b===\"checkbox\"?c=a.checked:b===\"select-multiple\"?c=a.selectedIndex>-1?f.map(a.options,function(a){return a.selected}).join(\"-\"):\"\":f.nodeName(a,\"select\")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,\"_change_data\"),g=H(d),(c.type!==\"focusout\"||d.type!==\"radio\")&&f._data(d,\"_change_data\",g);if(e===b||g===e)return;if(e!=null||g)c.type=\"change\",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,\"input\")?b.type:\"\";(c===\"radio\"||c===\"checkbox\"||f.nodeName(b,\"select\"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,\"input\")?b.type:\"\";(a.keyCode===13&&!f.nodeName(b,\"textarea\")||a.keyCode===32&&(c===\"checkbox\"||c===\"radio\")||c===\"select-multiple\")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,\"_change_data\",H(b))}},setup:function(a,b){if(this.type===\"file\")return!1;for(var c in G)f.event.add(this,c+\".specialChange\",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,\".specialChange\");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:\"focusin\",blur:\"focusout\"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each([\"bind\",\"one\"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a==\"object\"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c===\"one\"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a===\"unload\"&&c!==\"one\")this.one(a,d,e);else for(var i=0,j=this.length;i<j;i++)f.event.add(this[i],a,g,d);return this}}),f.fn.extend({unbind:function(a,b){if(typeof a==\"object\"&&!a.preventDefault)for(var c in a)this.unbind(c,a[c]);else for(var d=0,e=this.length;d<e;d++)f.event.remove(this[d],a,b);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind(\"live\"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f.data(this,\"lastToggle\"+a.guid)||0)%d;f.data(this,\"lastToggle\"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var K={focus:\"focusin\",blur:\"focusout\",mouseenter:\"mouseover\",mouseleave:\"mouseout\"};f.each([\"live\",\"die\"],function(a,c){f.fn[c]=function(a,d,e,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:f(this.context);if(typeof a==\"object\"&&!a.preventDefault){for(var o in a)n[c](o,d,a[o],m);return this}if(c===\"die\"&&!a&&g&&g.charAt(0)===\".\"){n.unbind(g);return this}if(d===!1||f.isFunction(d))e=d||C,d=b;a=(a||\"\").split(\" \");while((h=a[i++])!=null){j=w.exec(h),k=\"\",j&&(k=j[0],h=h.replace(w,\"\"));if(h===\"hover\"){a.push(\"mouseenter\"+k,\"mouseleave\"+k);continue}l=h,K[h]?(a.push(K[h]+k),h=h+k):h=(K[h]||h)+k;if(c===\"live\")for(var p=0,q=n.length;p<q;p++)f.event.add(n[p],\"live.\"+M(h,m),{data:d,selector:m,handler:e,origType:h,origHandler:e,preType:l});else n.unbind(\"live.\"+M(h,m),e)}return this}}),f.each(\"blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error\".split(\" \"),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!=\"string\"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^\\[\\]]*\\]|['\"][^'\"]*['\"]|[^\\[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\\\/g,j=/\\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=\"string\")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(\"\"),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]===\"~\"||x[0]===\"+\")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r=\"\",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)===\"[object Array]\")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!==\"\\\\\"){g[1]=(g[1]||\"\").replace(i,\"\"),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],\"\");break}}}}d||(d=typeof b.getElementsByTagName!=\"undefined\"?b.getElementsByTagName(\"*\"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)===\"\\\\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(!f)g=o=!0;else if(f===!0)continue}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],\"\");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw\"Syntax error, unrecognized expression: \"+a};var l=k.selectors={order:[\"ID\",\"NAME\",\"TAG\"],match:{ID:/#((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,CLASS:/\\.((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,NAME:/\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)['\"]*\\]/,ATTR:/\\[\\s*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(?:(['\"])(.*?)\\3|(#?(?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)*)|)|)\\s*\\]/,TAG:/^((?:[\\w\\u00c0-\\uFFFF\\*\\-]|\\\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\\(\\s*(even|odd|(?:[+\\-]?\\d+|(?:[+\\-]?\\d*)?n\\s*(?:[+\\-]\\s*\\d+)?))\\s*\\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^\\-]|$)/,PSEUDO:/:((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/},leftMatch:{},attrMap:{\"class\":\"className\",\"for\":\"htmlFor\"},attrHandle:{href:function(a){return a.getAttribute(\"href\")},type:function(a){return a.getAttribute(\"type\")}},relative:{\"+\":function(a,b){var c=typeof b==\"string\",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},\">\":function(a,b){var c,d=typeof b==\"string\",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},\"\":function(a,b,c){var e,f=d++,g=u;typeof b==\"string\"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g(\"parentNode\",b,f,a,e,c)},\"~\":function(a,b,c){var e,f=d++,g=u;typeof b==\"string\"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g(\"previousSibling\",b,f,a,e,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!=\"undefined\"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!=\"undefined\"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute(\"name\")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!=\"undefined\")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=\" \"+a[1].replace(i,\"\")+\" \";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(\" \"+h.className+\" \").replace(/[\\t\\n\\r]/g,\" \").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,\"\")},TAG:function(a,b){return a[1].replace(i,\"\").toLowerCase()},CHILD:function(a){if(a[1]===\"nth\"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\\+|\\s*/g,\"\");var b=/(-?)(\\d*)(?:n([+\\-]?\\d*))?/.exec(a[2]===\"even\"&&\"2n\"||a[2]===\"odd\"&&\"2n+1\"||!/\\D/.test(a[2])&&\"0n+\"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,\"\");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||\"\").replace(i,\"\"),a[2]===\"~=\"&&(a[4]=\" \"+a[4]+\" \");return a},PSEUDO:function(b,c,d,e,f){if(b[1]===\"not\")if((a.exec(b[3])||\"\").length>1||/^\\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!==\"hidden\"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute(\"type\"),c=a.type;return a.nodeName.toLowerCase()===\"input\"&&\"text\"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"radio\"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"checkbox\"===a.type},file:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"file\"===a.type},password:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"password\"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b===\"input\"||b===\"button\")&&\"submit\"===a.type},image:function(a){return a.nodeName.toLowerCase()===\"input\"&&\"image\"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b===\"input\"||b===\"button\")&&\"reset\"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b===\"input\"&&\"button\"===a.type||b===\"button\"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e===\"contains\")return(a.textContent||a.innerText||k.getText([a])||\"\").indexOf(b[3])>=0;if(e===\"not\"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case\"only\":case\"first\":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c===\"first\")return!0;d=a;case\"last\":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case\"nth\":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute(\"id\")===b},TAG:function(a,b){return b===\"*\"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(\" \"+(a.className||a.getAttribute(\"class\"))+\" \").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+\"\",f=b[2],g=b[4];return d==null?f===\"!=\":f===\"=\"?e===g:f===\"*=\"?e.indexOf(g)>=0:f===\"~=\"?(\" \"+e+\" \").indexOf(g)>=0:g?f===\"!=\"?e!==g:f===\"^=\"?e.indexOf(g)===0:f===\"$=\"?e.substr(e.length-g.length)===g:f===\"|=\"?e===g||e.substr(0,g.length+1)===g+\"-\":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return\"\\\\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\\[]*\\])(?![^\\(]*\\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\\r|\\n)*?)/.source+l.match[o].source.replace(/\\\\(\\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)===\"[object Array]\")Array.prototype.push.apply(d,a);else if(typeof a.length==\"number\")for(var f=a.length;c<f;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){if(a===b){g=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b=\"\",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement(\"div\"),d=\"script\"+(new Date).getTime(),e=c.documentElement;a.innerHTML=\"<a name='\"+d+\"'/>\",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!=\"undefined\"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=\"undefined\"&&e.getAttributeNode(\"id\").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=\"undefined\"&&a.getAttributeNode(\"id\");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement(\"div\");a.appendChild(c.createComment(\"\")),a.getElementsByTagName(\"*\").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]===\"*\"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML=\"<a href='#'></a>\",a.firstChild&&typeof a.firstChild.getAttribute!=\"undefined\"&&a.firstChild.getAttribute(\"href\")!==\"#\"&&(l.attrHandle.href=function(a){return a.getAttribute(\"href\",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement(\"div\"),d=\"__sizzle__\";b.innerHTML=\"<p class='TEST'></p>\";if(!b.querySelectorAll||b.querySelectorAll(\".TEST\").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\\w+$)|^\\.([\\w\\-]+$)|^#([\\w\\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b===\"body\"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!==\"object\"){var m=e,n=e.getAttribute(\"id\"),o=n||d,q=e.parentNode,r=/^\\s*[+~]/.test(b);n?o=o.replace(/'/g,\"\\\\$&\"):e.setAttribute(\"id\",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll(\"[id='\"+o+\"'] \"+b),f)}catch(s){}finally{n||m.removeAttribute(\"id\")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement(\"div\"),\"div\"),e=!1;try{b.call(c.documentElement,\"[test!='']:sizzle\")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g,\"='$1']\");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement(\"div\");a.innerHTML=\"<div class='test e'></div><div class='test'></div>\";if(!!a.getElementsByClassName&&a.getElementsByClassName(\"e\").length!==0){a.lastChild.className=\"e\";if(a.getElementsByClassName(\"e\").length===1)return;l.order.splice(1,0,\"CLASS\"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=\"undefined\"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!==\"HTML\":!1};var v=function(a,b){var c,d=[],e=\"\",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,\"\");a=l.relative[a]?a+\"*\":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};f.find=k,f.expr=k.selectors,f.expr[\":\"]=f.expr.filters,f.unique=k.uniqueSort,f.text=k.getText,f.isXMLDoc=k.isXML,f.contains=k.contains}();var N=/Until$/,O=/^(?:parents|prevUntil|prevAll)/,P=/,/,Q=/^.[^:#\\[\\.,]*$/,R=Array.prototype.slice,S=f.expr.match.POS,T={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!=\"string\")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack(\"\",\"find\",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(V(this,a,!1),\"not\",a)},filter:function(a){return this.pushStack(V(this,a,!0),\"filter\",a)},is:function(a){return!!a&&(typeof a==\"string\"?f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d<e;d++)i=a[d],j[i]||(j[i]=S.test(i)?f(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!=\"string\"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(l?l.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,\"closest\",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a==\"string\")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==\"string\"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,\"parentNode\")},parentsUntil:function(a,b,c){return f.dir(a,\"parentNode\",c)},next:function(a){return f.nth(a,2,\"nextSibling\")},prev:function(a){return f.nth(a,2,\"previousSibling\")},nextAll:function(a){return f.dir(a,\"nextSibling\")},prevAll:function(a){return f.dir(a,\"previousSibling\")},nextUntil:function(a,b,c){return f.dir(a,\"nextSibling\",c)},prevUntil:function(a,b,c){return f.dir(a,\"previousSibling\",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,\"iframe\")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d==\"string\"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(\",\"))}}),f.extend({filter:function(a,b,c){c&&(a=\":not(\"+a+\")\");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\\d+=\"(?:\\d+|null)\"/g,X=/^\\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,Z=/<([\\w:]+)/,$=/<tbody/i,_=/<|&#?\\w+;/,ba=/<(?:script|object|embed|option|style)/i,bb=/checked\\s*(?:[^=]|=\\s*.checked.)/i,bc=/\\/(java|ecma)script/i,bd=/^\\s*<!(?:\\[CDATA\\[|\\-\\-)/,be={option:[1,\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],area:[1,\"<map>\",\"</map>\"],_default:[0,\"\",\"\"]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,\"div<div>\",\"</div>\"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!=\"object\"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,\"body\")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,\"before\",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,\"after\",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName(\"*\")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName(\"*\"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,\"\"):null;if(typeof a==\"string\"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||[\"\",\"\"])[1].toLowerCase()]){a=a.replace(Y,\"<$1></$2>\");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName(\"*\")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!=\"string\"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),\"replaceWith\",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j==\"string\"&&bb.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,\"tr\");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bf(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bl)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i;b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof a[0]==\"string\"&&a[0].length<512&&i===c&&a[0].charAt(0)===\"<\"&&!ba.test(a[0])&&(f.support.checkClone||!bb.test(a[0]))&&(g=!0,h=f.fragments[a[0]],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean\n(a,i,e,d)),g&&(f.fragments[a[0]]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement==\"undefined\"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k==\"number\"&&(k+=\"\");if(!k)continue;if(typeof k==\"string\")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,\"<$1></$2>\");var l=(Z.exec(k)||[\"\",\"\"])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement(\"div\");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l===\"table\"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===\"<table>\"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],\"tbody\")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)==\"number\")for(i=0;i<r;i++)bk(k[i]);else bk(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||bc.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],\"script\")&&(!h[j].type||h[j].type.toLowerCase()===\"text/javascript\"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName(\"script\"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.expando,g=f.event.special,h=f.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&f.noData[j.nodeName.toLowerCase()])continue;c=j[f.expando];if(c){b=d[c]&&d[c][e];if(b&&b.events){for(var k in b.events)g[k]?f.event.remove(j,k):f.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[f.expando]:j.removeAttribute&&j.removeAttribute(f.expando),delete d[c]}}}});var bm=/alpha\\([^)]*\\)/i,bn=/opacity=([^)]*)/,bo=/([A-Z]|^ms)/g,bp=/^-?\\d+(?:px)?$/i,bq=/^-?\\d/,br=/^([\\-+])=([\\-+.\\de]+)/,bs={position:\"absolute\",visibility:\"hidden\",display:\"block\"},bt=[\"Left\",\"Right\"],bu=[\"Top\",\"Bottom\"],bv,bw,bx;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bv(a,\"opacity\",\"opacity\");return c===\"\"?\"1\":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":f.support.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&\"get\"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h===\"string\"&&(g=br.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h=\"number\");if(d==null||h===\"number\"&&isNaN(d))return;h===\"number\"&&!f.cssNumber[i]&&(d+=\"px\");if(!k||!(\"set\"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c===\"cssFloat\"&&(c=\"float\");if(g&&\"get\"in g&&(e=g.get(a,!0,d))!==b)return e;if(bv)return bv(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each([\"height\",\"width\"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return by(a,b,d);f.swap(a,bs,function(){e=by(a,b,d)});return e}},set:function(a,b){if(!bp.test(b))return b;b=parseFloat(b);if(b>=0)return b+\"px\"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||\"\")?parseFloat(RegExp.$1)/100+\"\":b?\"1\":\"\"},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?\"\":\"alpha(opacity=\"+b*100+\")\",g=d&&d.filter||c.filter||\"\";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,\"\"))===\"\"){c.removeAttribute(\"filter\");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+\" \"+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:\"inline-block\"},function(){b?c=bv(a,\"margin-right\",\"marginRight\"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,\"-$1\").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===\"\"&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b===\"fontSize\"?\"1em\":d||0,d=f.pixelLeft+\"px\",f.left=c,e&&(a.runtimeStyle.left=e));return d===\"\"?\"auto\":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,\"display\"))===\"none\"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\\[\\]$/,bB=/\\r?\\n/g,bC=/#.*$/,bD=/^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\\-storage|.+\\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\\/\\//,bI=/\\?/,bJ=/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\\s+/,bM=/([?&])_=[^&]*/,bN=/^([\\w\\+\\.\\-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=[\"*/\"]+[\"*\"];try{bR=e.href}catch(bU){bR=c.createElement(\"a\"),bR.href=\"\",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!=\"string\"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(\" \");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h=\"GET\";c&&(f.isFunction(c)?(d=c,c=b):typeof c==\"object\"&&(c=f.param(c,f.ajaxSettings.traditional),h=\"POST\"));var i=this;f.ajax({url:a,type:h,dataType:\"html\",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f(\"<div>\").append(c.replace(bJ,\"\")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,\"\\r\\n\")}}):{name:b.name,value:c.replace(bB,\"\\r\\n\")}}).get()}}),f.each(\"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split(\" \"),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each([\"get\",\"post\"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,\"script\")},getJSON:function(a,b,c){return f.get(a,b,c,\"json\")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:\"GET\",contentType:\"application/x-www-form-urlencoded\",processData:!0,async:!0,accepts:{xml:\"application/xml, text/xml\",html:\"text/html\",text:\"text/plain\",json:\"application/json, text/javascript\",\"*\":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:\"responseXML\",text:\"responseText\"},converters:{\"* text\":a.String,\"text html\":!0,\"text json\":f.parseJSON,\"text xml\":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||\"\",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader(\"Last-Modified\"))f.lastModified[k]=y;if(z=v.getResponseHeader(\"Etag\"))f.etag[k]=z}if(a===304)w=\"notmodified\",o=!0;else try{r=b$(d,x),w=\"success\",o=!0}catch(A){w=\"parsererror\",u=A}}else{u=w;if(!w||a)w=\"error\",a<0&&(a=0)}v.status=a,v.statusText=\"\"+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger(\"ajax\"+(o?\"Success\":\"Error\"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger(\"ajaxComplete\",[v,d]),--f.active||f.event.trigger(\"ajaxStop\"))}}typeof a==\"object\"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||\"abort\",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+\"\").replace(bC,\"\").replace(bH,bS[1]+\"//\"),d.dataTypes=f.trim(d.dataType||\"*\").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]===\"http:\"?80:443))==(bS[3]||(bS[1]===\"http:\"?80:443)))),d.data&&d.processData&&typeof d.data!=\"string\"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger(\"ajaxStart\");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?\"&\":\"?\")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,\"$1_=\"+x);d.url=y+(y===d.url?(bI.test(d.url)?\"&\":\"?\")+\"_=\"+x:\"\")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader(\"Content-Type\",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader(\"If-Modified-Since\",f.lastModified[k]),f.etag[k]&&v.setRequestHeader(\"If-None-Match\",f.etag[k])),v.setRequestHeader(\"Accept\",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!==\"*\"?\", \"+bT+\"; q=0.01\":\"\"):d.accepts[\"*\"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,\"No Transport\");else{v.readyState=1,t&&g.trigger(\"ajaxSend\",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort(\"timeout\")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+\"=\"+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join(\"&\").replace(bz,\"+\")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\\=)\\?(&|$)|\\?\\?/i;f.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){return f.expando+\"_\"+b_++}}),f.ajaxPrefilter(\"json jsonp\",function(b,c,d){var e=b.contentType===\"application/x-www-form-urlencoded\"&&typeof b.data==\"string\";if(b.dataTypes[0]===\"jsonp\"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l=\"$1\"+h+\"$2\";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\\?/.test(j)?\"&\":\"?\")+b.jsonp+\"=\"+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters[\"script json\"]=function(){g||f.error(h+\" was not called\");return g[0]},b.dataTypes[0]=\"json\";return\"script\"}}),f.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/javascript|ecmascript/},converters:{\"text script\":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter(\"script\",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type=\"GET\",a.global=!1)}),f.ajaxTransport(\"script\",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName(\"head\")[0]||c.documentElement;return{send:function(f,g){d=c.createElement(\"script\"),d.async=\"async\",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,\"success\")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&\"withCredentials\"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e[\"X-Requested-With\"]&&(e[\"X-Requested-With\"]=\"XMLHttpRequest\");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=\"\"}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\\-]=)?([\\d+.\\-]+)([a-z%]*)$/i,cl,cm=[[\"height\",\"marginTop\",\"marginBottom\",\"paddingTop\",\"paddingBottom\"],[\"width\",\"marginLeft\",\"marginRight\",\"paddingLeft\",\"paddingRight\"],[\"opacity\"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq(\"show\",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,\"olddisplay\")&&e===\"none\"&&(e=d.style.display=\"\"),e===\"\"&&f.css(d,\"display\")===\"none\"&&f._data(d,\"olddisplay\",cr(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===\"\"||e===\"none\")d.style.display=f._data(d,\"olddisplay\")||\"\"}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cq(\"hide\",3),a,b,c);for(var d=0,e=this.length;d<e;d++)if(this[d].style){var g=f.css(this[d],\"display\");g!==\"none\"&&!f._data(this[d],\"olddisplay\")&&f._data(this[d],\"olddisplay\",g)}for(d=0;d<e;d++)this[d].style&&(this[d].style.display=\"none\");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a==\"boolean\";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(\":hidden\");f(this)[b?\"show\":\"hide\"]()}):this.animate(cq(\"toggle\",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(\":hidden\").css(\"opacity\",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return this[e.queue===!1?\"each\":\"queue\"](function(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(\":hidden\"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||\"swing\";if(h===\"hide\"&&d||h===\"show\"&&!d)return b.complete.call(this);c&&(g===\"height\"||g===\"width\")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,\"display\")===\"inline\"&&f.css(this,\"float\")===\"none\"&&(f.support.inlineBlockNeedsLayout?(j=cr(this.nodeName),j===\"inline\"?this.style.display=\"inline-block\":(this.style.display=\"inline\",this.style.zoom=1)):this.style.display=\"inline-block\"))}b.overflow!=null&&(this.style.overflow=\"hidden\");for(i in a)k=new f.fx(this,b,i),h=a[i],cj.test(h)?k[h===\"toggle\"?d?\"show\":\"hide\":h]():(l=ck.exec(h),m=k.cur(),l?(n=parseFloat(l[2]),o=l[3]||(f.cssNumber[i]?\"\":\"px\"),o!==\"px\"&&(f.style(this,i,(n||1)+o),m=(n||1)/k.cur()*m,f.style(this,i,m+o)),l[1]&&(n=(l[1]===\"-=\"?-1:1)*n+m),k.custom(m,n,o)):k.custom(m,h,\"\"));return!0})},stop:function(a,b){a&&this.queue([]),this.each(function(){var a=f.timers,c=a.length;b||f._unmark(!0,this);while(c--)a[c].elem===this&&(b&&a[c](!0),a.splice(c,1))}),b||this.dequeue();return this}}),f.each({slideDown:cq(\"show\",1),slideUp:cq(\"hide\",1),slideToggle:cq(\"toggle\",1),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a==\"object\"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration==\"number\"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default,d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue!==!1?f.dequeue(this):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b===\"auto\"?0:b:a},custom:function(a,b,c){function g(a){return d.step(a)}var d=this,e=f.fx;this.startTime=cn||co(),this.start=a,this.end=b,this.unit=c||this.unit||(f.cssNumber[this.prop]?\"\":\"px\"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&f.timers.push(g)&&!cl&&(cl=setInterval(e.tick,e.interval))},show:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop===\"width\"||this.prop===\"height\"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=cn||co(),c=!0,d=this.elem,e=this.options,g,h;if(a||b>=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each([\"\",\"X\",\"Y\"],function(a,b){d.style[\"overflow\"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b<a.length;++b)a[b]()||a.splice(b--,1);a.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cl),cl=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,\"opacity\",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop===\"width\"||a.prop===\"height\"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cs=/^t(?:able|d|h)$/i,ct=/^(?:body|html)$/i;\"getBoundingClientRect\"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cu(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);f.offset.initialize();var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.offset.supportsFixedPosition&&k.position===\"fixed\")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.offset.doesNotAddBorder&&(!f.offset.doesAddBorderForTableAndCells||!cs.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.offset.subtractsBorderForOverflowNotVisible&&c.overflow!==\"visible\"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position===\"relative\"||k.position===\"static\")l+=i.offsetTop,m+=i.offsetLeft;f.offset.supportsFixedPosition&&k.position===\"fixed\"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={initialize:function(){var a=c.body,b=c.createElement(\"div\"),d,e,g,h,i=parseFloat(f.css(a,\"marginTop\"))||0,j=\"<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>\";f.extend(b.style,{position:\"absolute\",top:0,left:0,margin:0,border:0,width:\"1px\",height:\"1px\",visibility:\"hidden\"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position=\"fixed\",e.style.top=\"20px\",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top=\"\",d.style.overflow=\"hidden\",d.style.position=\"relative\",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,\"marginTop\"))||0,c+=parseFloat(f.css(a,\"marginLeft\"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,\"position\");d===\"static\"&&(a.style.position=\"relative\");var e=f(a),g=e.offset(),h=f.css(a,\"top\"),i=f.css(a,\"left\"),j=(d===\"absolute\"||d===\"fixed\")&&f.inArray(\"auto\",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),\"using\"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,\"marginTop\"))||0,c.left-=parseFloat(f.css(a,\"marginLeft\"))||0,d.top+=parseFloat(f.css(b[0],\"borderTopWidth\"))||0,d.left+=parseFloat(f.css(b[0],\"borderLeftWidth\"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,\"position\")===\"static\")a=a.offsetParent;return a})}}),f.each([\"Left\",\"Top\"],function(a,c){var d=\"scroll\"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?\"pageXOffset\"in g?g[a?\"pageYOffset\":\"pageXOffset\"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each([\"Height\",\"Width\"],function(a,c){var d=c.toLowerCase();f.fn[\"inner\"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,\"padding\")):null},f.fn[\"outer\"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?\"margin\":\"border\")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement[\"client\"+c],h=e.document.body;return e.document.compatMode===\"CSS1Compat\"&&g||h&&h[\"client\"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement[\"client\"+c],e.body[\"scroll\"+c],e.documentElement[\"scroll\"+c],e.body[\"offset\"+c],e.documentElement[\"offset\"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a==\"string\"?a:a+\"px\")}}),a.jQuery=a.$=f})(window);"
  },
  {
    "path": "res/js/session.js",
    "content": "var socket = io.connect();\nvar connectNum=0;\nvar pproxy_colors=[\"#FFFFFF\",\"#CCFFFF\",\"#FFCCCC\",\"#99CCCC\",\"996699\",\"#CC9999\",\"#0099CC\",\"#FFFF66\",\"#336633\",\"#99CC00\"]\n\nvar ip_colors={} \nvar pproxy_session_max_len=0;\nvar pproxy_table_max_row=2000;\n\n\nvar pproxy_req_list=[];\n\nif(window.localStorage){\n\tpproxy_req_list=$.parseJSON(window.localStorage[\"reqs\"]||\"[]\")\n\tpproxy_session_max_len=1000;\n}\n\nfunction pproxy_show_reqs_from_local(){\n\tfor(var i=0;i<pproxy_req_list.length;i++){\n\t\tpproxy_show_req(pproxy_req_list[i]);\n\t}\n}\n\nwindow.onbeforeunload=function(){\n\tif(pproxy_session_max_len>0){\n\t\twindow.localStorage[\"reqs\"]=JSON.stringify(pproxy_req_list);\n\t}\n}\n\nfunction pproxy_save_req_local(dataStr64){\n\tif(pproxy_session_max_len<1){\n\t\treturn;\n\t}\n\tvar n=pproxy_req_list.push(dataStr64)\n\tif(n>pproxy_session_max_len){\n\t\tpproxy_req_list.shift();\n\t}\n}\n\nfunction pporxy_session_clean(){\n\tpproxy_req_list=[];\n\t$('#tb_network tbody').empty();\n}\n\nfunction pproxy_log(msg){\n\t$(\"#log_div\").append(\"<div>\"+(new Date().toString())+\":\"+msg+\"</div>\");\n}\n\n\nfunction pproxy_net_local_filter(host,path){\n\tif(!_pproxy_filter(host,$(\"#net_local_host\").val())){\n\t\treturn false;\n\t}\n\tif(!_pproxy_filter(path,$(\"#net_local_path\").val())){\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nfunction _pproxy_filter(kw,kwstr){\n\tif(kwstr==\"\"){\n\t\treturn true;\n\t}\n\tvar kws=(kwstr+\"\").split(\"|\");\n\tkw+=\"\";\n\tvar tmp=[]\t\n\tfor(var i in kws){\n\t\tvar _kw=$.trim(kws[i]+\"\");\n\t\tif(_kw!=\"\"){\n\t\t\ttmp.push(_kw);\n\t\t}\n\t}\n\tif(tmp.length==0){\n\t\treturn true;\n\t}\n\tfor (var i in tmp){\n\t\tif(kw.indexOf(tmp[i])!=-1){\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nsocket.on('connect', function() {\n\tconnectNum++\n\tif(connectNum>1){\n\t\tpproxy_log(\"ws error.connectNum=\"+connectNum);\n\t\tsocket.emit(\"disconnect\");\n\t\treturn;\n\t}\n    $(\"#connect_status\").html(\"online\")\n    $(\"#network_filter_form\").change();\n});\n\nsocket.on(\"disconnect\", function() {\n\tconnectNum--;\n    $(\"#connect_status\").html(\"<font color=pink>offline</font>\");\n});\n\nsocket.on(\"hello\",function(data){\n\tconsole && console.log(new Date().toString(),data);\n});\n\nfunction pproxy_getColor(addr){\n\tvar info=addr.split(\":\");\n\tif(info.length!=2){\n\t\treturn \"#FFFFFF\";\n\t}\n\tvar ip=info[0];\n\tvar color=ip_colors[ip];\n\tif(!color){\n\t\tvar l=0;\n\t\tfor(var _t in ip_colors){\n\t\t\tl++;\n\t\t}\n\t\tcolor=pproxy_colors[l% pproxy_colors.length];\n\t\tip_colors[ip]=color;\n\t}\n\treturn color\n}\n\n\nfunction pproxy_show_req(data) {\n\tconsole && console.log(\"pproxy_show_req:\",data)\n//    var dataStr=Base64.decode(dataStr64+\"\");\n//\tvar data={};\n//\ttry{\n//\t\tdata=$.parseJSON(dataStr)\n//\t}catch(e){\n//\t\tconsole && console.log(\"parseJSON_error-pproxy_show_req\",e,\"datastr:\",dataStr)\n//\t\treturn\n//\t}\n\t\n//    console && console.log(\"req\", data)\n    var html=\"<tr onclick=\\\"get_response(this,'\" + data['docid'] + \"')\\\" \";\n\tvar cls=[]\n    if(data[\"replay\"]){\n    \tcls.push(\"replay\");\n    }\n\tif(!pproxy_net_local_filter(data[\"host\"],data[\"path\"])){\n\t\tcls.push(\"hide\");\n\t}\n\t\n\tif(cls.length>0){\n    \thtml+=\"class='\"+cls.join(\" \")+\"' \";\n\t}\n    html+=\" data-ip='\"+data[\"client_ip\"]+\"' data-host='\"+h(data[\"host\"])+\"' data-path='\"+h(data[\"path\"])+\"'>\" \n    + \"<td bgcolor='\"+pproxy_getColor(data[\"client_ip\"])+\"'>\" + data[\"sid\"] + \"</td>\"\n    + \"<td><div class='oneline' title='\"+h(data[\"host\"])+\"'>\" + data[\"host\"] + \"</div></td>\" +\n    \"<td><div class='oneline' title='\"+h(data[\"url\"])+\"'>\" +data[\"method\"]+\"&nbsp;\"+ h(data[\"path\"])+ \"</div></td>\" + \n    \"</tr>\";\n    var tb=$(\"#tb_network tbody\");\n    tb.prepend(html);\n    \n    if(Math.random()*100>95 && tb.find(\"tr\").size()>pproxy_table_max_row*1.5){\n    \ttb.find(\"tr:gt(\"+pproxy_table_max_row+\")\").each(function(){\n    \t\t$(this).remove();\n    \t});\n    }\n}\n\n\nsocket.on(\"req\",function(data){\n\tconsole && console.log(\"on.req\",\"data:\",data);\n\tpproxy_save_req_local(data);\n\tpproxy_show_req(data);\n});\n\n\nsocket.on(\"user_num\", function(data) {\n\t$(\"#user_num_online\").html(data);\n});\n\nsocket.on(\"res\",\n        function(data) {\n\t\t\tconsole && console.log(\"on.res\",\"data:\",data)\n//\t        var dataStr=Base64.decode(dataStr64+\"\");\n//\t\t\ttry{\n//\t\t\t\tvar data=$.parseJSON(dataStr)\n//\t\t\t}catch(e){\n//\t\t\t\tconsole && console.log(\"parseJSON_error on.res:\",e)\n//\t\t\t\treturn\n//\t\t\t}\n//\t\t\tconsole && console.log(data)\n            var req = data[\"req\"];\n            var res = data[\"res\"];\n            var html=\"\";\n            if(req){\n\t            var re_do_str=req[\"schema\"]==\"http\"?(\"&nbsp;<a target='_blank' href='/replay?id=\"+req[\"id\"]+\"'>replay</a>\"):\"\";\n\t            \n\t            html += \"<div><table class='tb_1'><caption>Request\"+re_do_str+pproxy_timeformat(req[\"now\"])+\"</caption>\";\n\t            html += \"<tr><th width='80px'>url</th><td>\" + h(req[\"url\"]) + \"&nbsp;&nbsp;<a href='\"+h(req[\"url\"])+\"' target='_blank'>view</a></td></tr>\"\n\t            if (req[\"url_origin\"]!=req[\"url\"]) {\n\t                html += \"<tr><th>origin</th><td><span style='color:blue'>\" + h(req[\"url_origin\"]) + \"</span></td></tr>\";\n\t            }\n\t            if (req[\"msg\"]) {\n\t            \thtml += \"<tr><th>msg</th><td><span style='color:red'>\" + h(req[\"msg\"])+\"</span></td></tr>\";\n\t            }\n\t            html += \"<tr><th>proxy_urer</th>\" +\n\t            \t\t\"<td><b>remote_addr : </b>&nbsp;\" +req[\"client_ip\"] + \"&nbsp;&nbsp;<b> docid : </b>&nbsp;\"+ req[\"id\"] + \n\t            \t\t\"</td></tr>\";\n\t            html += pproxy_tr_sub_table(req[\"form_get\"], \"get_params\");\n\t            html += pproxy_tr_sub_table(req[\"form_post\"], \"post_params\");\n\t            if (req[\"dump\"]) {\n\t                html += \"<tr><th>req_dump</th><td>\" + h(Base64.decode(req[\"dump\"])).replace(/\\n/g, \"<br/>\")\n\t                        + \"</td></tr>\";\n\t            }\n\t            html += \"</table></div>\";\n            }else{\n            \thtml=\"<br/><br/><br/><br/><center>request not exists!</center>\";\n            }\n            var res_link = \"\";\n            \n            var hideBigBody=false;\n            \n            if (res) {\n                res_link = \"<a href='/response?id=\" + res[\"id\"] + \"' target='_blank'>view</a>\";\n                html += \"<div><table class='tb_1'><caption>Response&nbsp;\" + res_link +pproxy_timeformat(res[\"now\"])+ \"</caption>\"\n                if (res[\"msg\"]) {\n\t            \thtml += \"<tr><th  width='80px'>msg</th><td><span style='color:red'>\" + h(res[\"msg\"])+\"</span></td></tr>\";\n\t            }\n                \n                if (res[\"dump\"]) {\n                    html += \"<tr><th width='80px'>res_dump</th><td>\" + h(Base64.decode(res[\"dump\"])).replace(/\\n/g, \"<br/>\")\n                    + \"</td></tr>\";\n                }\n                var body_str = Base64.decode(res[\"body\"])\n                var isImg = res[\"header\"][\"Content-Type\"] != undefined\n                        && res[\"header\"][\"Content-Type\"][0].indexOf(\"image\") > -1;\n\n                var isStatusOk = res[\"status\"] == 200;\n\n                var bd_json = pproxy_parseAsjson(body_str);\n\n                if (bd_json) {\n                \thideBigBody=true;\n                    html += \"<tr><th width='80px'>body_json</th><td>\" + bd_json + \"</td></tr>\";\n                }\n                if (isImg) {\n                \thideBigBody=true;\n                    html += \"<tr><th>body_img</th><td><img src='data:\" + res[\"header\"][\"Content-Type\"][0] + \";base64,\"\n                            + res[\"body\"] + \"'/></td></tr>\";\n                }\n                if (!isImg || res[\"body\"].length < 1000 || !isStatusOk) {\n                \thtml += \"<tr><th width='80px'>body\";\n                \tif(res[\"body\"].length>400){\n                \t\thtml+=\"<div><a href='#' onclick='return pproxy_res_td_body_toggle()'>toggle</a></div>\";\n                \t}else{\n                \t\thideBigBody=false;\n                \t}\n                \thtml+= \"</th>\" +\n                \t\t\t\"<td>\" +\n                \t\t\t\"<div id='res_td_body' \"+(hideBigBody?\"class='res_td_body' \":\"\")+\">\" + h(body_str).replace(/\\n/g, \"<br/>\") + \n                \t\t\t\"</div></td></tr>\";\n                }\n            }\n\n            html += \"</table></div>\";\n            $(\"#right_content\").empty().html(html).hide().slideDown(\"fast\");\n        })\n\nfunction pproxy_res_td_body_toggle(){\n\t$(\"#res_td_body\").toggleClass(\"res_td_body\");\n\treturn false;\n}\n\nfunction pproxy_timeformat(sec){\n\tif(!sec ||sec<1000){\n\t\treturn \"\";\n\t}\n\tvar numFill=function(num,len){\n\t\tnum=num+\"\";\n\t\tvar l=len-num.length;\n\t\tfor(;l>0;l--){\n\t\t\tnum=\"0\"+num;\n\t\t}\n\t\treturn num;\n\t}\n\tvar d=new Date()\n\td.setTime(sec*1000)\n\treturn \"&nbsp;<font size=-1>\"+d.getFullYear()+\"-\"+numFill(d.getMonth()+1,2)+\"-\"+numFill(d.getDate(),2)+\" \"\n\t\t   +numFill(d.getHours(),2)+\":\"+numFill(d.getMinutes(),2)+\":\"+numFill(d.getSeconds(),2)+\"</font>\";\n}\n\n        \nfunction pproxy_parseAsjson(str) {\n    try {\n    \tstr=str+\"\";\n    \tif(str[0]!=\"{\" && str[0]!=\"[\"){\n    \t\treturn false;\n    \t}\n        var jsonObj = JSON.parse(str);\n        if (jsonObj) {\n            var json_str = JSON.stringify(jsonObj, null, 4);\n            return \"<pre>\" + json_str + \"</pre>\";\n        }\n    } catch (e) {\n    \tconsole.log(\"pproxy_parseAsjson_error\",e);\n    }\n    return false;\n}\n\nfunction pproxy_tr_sub_table(obj, name) {\n    if (!obj) {\n        return \"\";\n    }\n    var html = \"<tr><th>\" + name + \"</th><td class='td_has_sub'><table class='tb_1'>\";\n    var i = 0;\n    var max_key_len=0;\n    for ( var k in obj) {\n    \tmax_key_len=Math.max(max_key_len,(k+\"\").length);\n    }\n    for ( var k in obj) {\n        html += \"<tr><th  \"+(max_key_len<40?\"width='120px' nowrap\":\"width='140px'\")+\">\" + k + \"</th><td><ul class='td_ul'>\";\n        for ( var i in obj[k]) {\n            html += \"<li>\";\n            var json_str = pproxy_parseAsjson(obj[k][i]);\n            if (json_str) {\n                html += json_str;\n            } else {\n                html += h(obj[k][i]);\n            }\n            html += \"</li>\";\n        }\n        html += \"</ul></td></tr>\";\n        i++;\n    }\n    if (i < 1) {\n        return \"\";\n    }\n    html += \"</table></td></tr>\"\n    return html;\n}\n\nfunction pproxy_show_response(docid){\n\tconsole && console.log(\"get_response start,docid=\", docid);\n    var loading_msg=\"loading...docid=\" + docid;\n    var isValidId=(docid+\"\").length>2;\n    if(!isValidId){\n    \tloading_msg=\"https request:no data\";\n    }else{\n    \tloading_msg+=\"&nbsp;<a href='javascript:;' onclick=\\\"pproxy_show_response('\"+docid+\"')\\\">reload</a>\";\n    }\n    $(\"#right_content\").empty().html(\"<center style='margin:200px 0 auto'>\"+loading_msg+\"</center>\");\n    if(!isValidId){\n    \treturn;\n    }\n\tsocket.emit(\"get_response\", docid);\n\tconsole.log && console.log(\"emit get_response,docid=\",docid);\n}\n\nfunction get_response(tr, docid) {\n    pproxy_show_response(docid);\n    $(tr).parent(\"tbody\").find(\"tr\").removeClass(\"selected\");\n    $(tr).addClass(\"selected\");\n    location.hash=\"req_\"+docid;\n}\n\nfunction bytesToString(bytes) {\n    var result = \"\";\n    for (var i = 0; i < bytes.length; i++) {\n        result += String.fromCharCode(parseInt(bytes[i], 2));\n    }\n    return result;\n}\n\nfunction h(html) {\n\tif(html==\"\"){\n\t\treturn \"&nbsp;\";\n\t}\n\thtml = (html+\"\").replace(/&/g, '&amp;')\n\t\t\t\t.replace(/</g, '&lt;')\n\t\t\t\t.replace(/>/g, '&gt;')\n\t\t\t    .replace(/'/g, '&acute;')\n\t\t\t    .replace(/\"/g, '&quot;')\n\t            .replace(/\\|/g, '&brvbar;');\n    return html;\n}\n\n$().ready(function() {\n\t$(\"#network_filter_form input:text\").each(function(){\n\t\tpproxy_local_save(this,$(this).attr(\"name\"));\n\t});\n\tvar filter_form=$(\"#network_filter_form\");\n\tfilter_form.change(function() {\n        var form_data = $(this).serialize();\n        socket.emit(\"client_filter\", form_data);\n    });\n    \n    setTimeout(function(){filter_form.change();},600);\n    setTimeout(function(){filter_form.change();},3000);\n    \n\tfilter_form.find(\"input:text\").keyup(function(){\n\t\tfilter_form.change();\n    });\n    \n    if(location.hash.match(/req_\\d+/)){\n        var docid=location.hash.substr(5);\n        setTimeout((function(id){\n        \treturn function(){\n        \t\tpproxy_show_response(id);\n        \t}\n        })(docid),500);\n    }\n    \n    setTimeout(pproxy_show_reqs_from_local,0);\n    \n    \n    $(\"#net_local_host,#net_local_path\").bind(\"keyup change\",function(){\n    \t$('#tb_network tbody tr').each(function(){\n    \t\tif(pproxy_net_local_filter($(this).data(\"host\"),$(this).data(\"path\"))){\n    \t\t\t$(this).removeClass(\"hide\");\n    \t\t}else{\n    \t\t\t$(this).addClass(\"hide\");\n    \t\t}\n    \t});\n    });\n});\n\nfunction pproxy_local_save(target,id){\n\tif(!window.localStorage){\n\t\treturn;\n\t}\n\t$(target).val(window.localStorage[id]||\"\").change(function(){\n\t\twindow.localStorage[id]=$(this).val();\n\t});\n}"
  },
  {
    "path": "res/js/socket.io.js",
    "content": "/*! Socket.IO.js build:0.9.10, development. Copyright(c) 2011 LearnBoost <dev@learnboost.com> MIT Licensed */\n\nvar io = ('undefined' === typeof module ? {} : module.exports);\n(function() {\n\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, global) {\n\n  /**\n   * IO namespace.\n   *\n   * @namespace\n   */\n\n  var io = exports;\n\n  /**\n   * Socket.IO version\n   *\n   * @api public\n   */\n\n  io.version = '0.9.10';\n\n  /**\n   * Protocol implemented.\n   *\n   * @api public\n   */\n\n  io.protocol = 1;\n\n  /**\n   * Available transports, these will be populated with the available transports\n   *\n   * @api public\n   */\n\n  io.transports = [];\n\n  /**\n   * Keep track of jsonp callbacks.\n   *\n   * @api private\n   */\n\n  io.j = [];\n\n  /**\n   * Keep track of our io.Sockets\n   *\n   * @api private\n   */\n  io.sockets = {};\n\n\n  /**\n   * Manages connections to hosts.\n   *\n   * @param {String} uri\n   * @Param {Boolean} force creation of new socket (defaults to false)\n   * @api public\n   */\n\n  io.connect = function (host, details) {\n    var uri = io.util.parseUri(host)\n      , uuri\n      , socket;\n\n    if (global && global.location) {\n      uri.protocol = uri.protocol || global.location.protocol.slice(0, -1);\n      uri.host = uri.host || (global.document\n        ? global.document.domain : global.location.hostname);\n      uri.port = uri.port || global.location.port;\n    }\n\n    uuri = io.util.uniqueUri(uri);\n\n    var options = {\n        host: uri.host\n      , secure: 'https' == uri.protocol\n      , port: uri.port || ('https' == uri.protocol ? 443 : 80)\n      , query: uri.query || ''\n    };\n\n    io.util.merge(options, details);\n\n    if (options['force new connection'] || !io.sockets[uuri]) {\n      socket = new io.Socket(options);\n    }\n\n    if (!options['force new connection'] && socket) {\n      io.sockets[uuri] = socket;\n    }\n\n    socket = socket || io.sockets[uuri];\n\n    // if path is different from '' or /\n    return socket.of(uri.path.length > 1 ? uri.path : '');\n  };\n\n})('object' === typeof module ? module.exports : (this.io = {}), this);\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, global) {\n\n  /**\n   * Utilities namespace.\n   *\n   * @namespace\n   */\n\n  var util = exports.util = {};\n\n  /**\n   * Parses an URI\n   *\n   * @author Steven Levithan <stevenlevithan.com> (MIT license)\n   * @api public\n   */\n\n  var re = /^(?:(?![^:@]+:[^:@\\/]*@)([^:\\/?#.]+):)?(?:\\/\\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;\n\n  var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password',\n               'host', 'port', 'relative', 'path', 'directory', 'file', 'query',\n               'anchor'];\n\n  util.parseUri = function (str) {\n    var m = re.exec(str || '')\n      , uri = {}\n      , i = 14;\n\n    while (i--) {\n      uri[parts[i]] = m[i] || '';\n    }\n\n    return uri;\n  };\n\n  /**\n   * Produces a unique url that identifies a Socket.IO connection.\n   *\n   * @param {Object} uri\n   * @api public\n   */\n\n  util.uniqueUri = function (uri) {\n    var protocol = uri.protocol\n      , host = uri.host\n      , port = uri.port;\n\n    if ('document' in global) {\n      host = host || document.domain;\n      port = port || (protocol == 'https'\n        && document.location.protocol !== 'https:' ? 443 : document.location.port);\n    } else {\n      host = host || 'localhost';\n\n      if (!port && protocol == 'https') {\n        port = 443;\n      }\n    }\n\n    return (protocol || 'http') + '://' + host + ':' + (port || 80);\n  };\n\n  /**\n   * Mergest 2 query strings in to once unique query string\n   *\n   * @param {String} base\n   * @param {String} addition\n   * @api public\n   */\n\n  util.query = function (base, addition) {\n    var query = util.chunkQuery(base || '')\n      , components = [];\n\n    util.merge(query, util.chunkQuery(addition || ''));\n    for (var part in query) {\n      if (query.hasOwnProperty(part)) {\n        components.push(part + '=' + query[part]);\n      }\n    }\n\n    return components.length ? '?' + components.join('&') : '';\n  };\n\n  /**\n   * Transforms a querystring in to an object\n   *\n   * @param {String} qs\n   * @api public\n   */\n\n  util.chunkQuery = function (qs) {\n    var query = {}\n      , params = qs.split('&')\n      , i = 0\n      , l = params.length\n      , kv;\n\n    for (; i < l; ++i) {\n      kv = params[i].split('=');\n      if (kv[0]) {\n        query[kv[0]] = kv[1];\n      }\n    }\n\n    return query;\n  };\n\n  /**\n   * Executes the given function when the page is loaded.\n   *\n   *     io.util.load(function () { console.log('page loaded'); });\n   *\n   * @param {Function} fn\n   * @api public\n   */\n\n  var pageLoaded = false;\n\n  util.load = function (fn) {\n    if ('document' in global && document.readyState === 'complete' || pageLoaded) {\n      return fn();\n    }\n\n    util.on(global, 'load', fn, false);\n  };\n\n  /**\n   * Adds an event.\n   *\n   * @api private\n   */\n\n  util.on = function (element, event, fn, capture) {\n    if (element.attachEvent) {\n      element.attachEvent('on' + event, fn);\n    } else if (element.addEventListener) {\n      element.addEventListener(event, fn, capture);\n    }\n  };\n\n  /**\n   * Generates the correct `XMLHttpRequest` for regular and cross domain requests.\n   *\n   * @param {Boolean} [xdomain] Create a request that can be used cross domain.\n   * @returns {XMLHttpRequest|false} If we can create a XMLHttpRequest.\n   * @api private\n   */\n\n  util.request = function (xdomain) {\n\n    if (xdomain && 'undefined' != typeof XDomainRequest) {\n      return new XDomainRequest();\n    }\n\n    if ('undefined' != typeof XMLHttpRequest && (!xdomain || util.ua.hasCORS)) {\n      return new XMLHttpRequest();\n    }\n\n    if (!xdomain) {\n      try {\n        return new window[(['Active'].concat('Object').join('X'))]('Microsoft.XMLHTTP');\n      } catch(e) { }\n    }\n\n    return null;\n  };\n\n  /**\n   * XHR based transport constructor.\n   *\n   * @constructor\n   * @api public\n   */\n\n  /**\n   * Change the internal pageLoaded value.\n   */\n\n  if ('undefined' != typeof window) {\n    util.load(function () {\n      pageLoaded = true;\n    });\n  }\n\n  /**\n   * Defers a function to ensure a spinner is not displayed by the browser\n   *\n   * @param {Function} fn\n   * @api public\n   */\n\n  util.defer = function (fn) {\n    if (!util.ua.webkit || 'undefined' != typeof importScripts) {\n      return fn();\n    }\n\n    util.load(function () {\n      setTimeout(fn, 100);\n    });\n  };\n\n  /**\n   * Merges two objects.\n   *\n   * @api public\n   */\n\n  util.merge = function merge (target, additional, deep, lastseen) {\n    var seen = lastseen || []\n      , depth = typeof deep == 'undefined' ? 2 : deep\n      , prop;\n\n    for (prop in additional) {\n      if (additional.hasOwnProperty(prop) && util.indexOf(seen, prop) < 0) {\n        if (typeof target[prop] !== 'object' || !depth) {\n          target[prop] = additional[prop];\n          seen.push(additional[prop]);\n        } else {\n          util.merge(target[prop], additional[prop], depth - 1, seen);\n        }\n      }\n    }\n\n    return target;\n  };\n\n  /**\n   * Merges prototypes from objects\n   *\n   * @api public\n   */\n\n  util.mixin = function (ctor, ctor2) {\n    util.merge(ctor.prototype, ctor2.prototype);\n  };\n\n  /**\n   * Shortcut for prototypical and static inheritance.\n   *\n   * @api private\n   */\n\n  util.inherit = function (ctor, ctor2) {\n    function f() {};\n    f.prototype = ctor2.prototype;\n    ctor.prototype = new f;\n  };\n\n  /**\n   * Checks if the given object is an Array.\n   *\n   *     io.util.isArray([]); // true\n   *     io.util.isArray({}); // false\n   *\n   * @param Object obj\n   * @api public\n   */\n\n  util.isArray = Array.isArray || function (obj) {\n    return Object.prototype.toString.call(obj) === '[object Array]';\n  };\n\n  /**\n   * Intersects values of two arrays into a third\n   *\n   * @api public\n   */\n\n  util.intersect = function (arr, arr2) {\n    var ret = []\n      , longest = arr.length > arr2.length ? arr : arr2\n      , shortest = arr.length > arr2.length ? arr2 : arr;\n\n    for (var i = 0, l = shortest.length; i < l; i++) {\n      if (~util.indexOf(longest, shortest[i]))\n        ret.push(shortest[i]);\n    }\n\n    return ret;\n  }\n\n  /**\n   * Array indexOf compatibility.\n   *\n   * @see bit.ly/a5Dxa2\n   * @api public\n   */\n\n  util.indexOf = function (arr, o, i) {\n\n    for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;\n         i < j && arr[i] !== o; i++) {}\n\n    return j <= i ? -1 : i;\n  };\n\n  /**\n   * Converts enumerables to array.\n   *\n   * @api public\n   */\n\n  util.toArray = function (enu) {\n    var arr = [];\n\n    for (var i = 0, l = enu.length; i < l; i++)\n      arr.push(enu[i]);\n\n    return arr;\n  };\n\n  /**\n   * UA / engines detection namespace.\n   *\n   * @namespace\n   */\n\n  util.ua = {};\n\n  /**\n   * Whether the UA supports CORS for XHR.\n   *\n   * @api public\n   */\n\n  util.ua.hasCORS = 'undefined' != typeof XMLHttpRequest && (function () {\n    try {\n      var a = new XMLHttpRequest();\n    } catch (e) {\n      return false;\n    }\n\n    return a.withCredentials != undefined;\n  })();\n\n  /**\n   * Detect webkit.\n   *\n   * @api public\n   */\n\n  util.ua.webkit = 'undefined' != typeof navigator\n    && /webkit/i.test(navigator.userAgent);\n\n   /**\n   * Detect iPad/iPhone/iPod.\n   *\n   * @api public\n   */\n\n  util.ua.iDevice = 'undefined' != typeof navigator\n      && /iPad|iPhone|iPod/i.test(navigator.userAgent);\n\n})('undefined' != typeof io ? io : module.exports, this);\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io) {\n\n  /**\n   * Expose constructor.\n   */\n\n  exports.EventEmitter = EventEmitter;\n\n  /**\n   * Event emitter constructor.\n   *\n   * @api public.\n   */\n\n  function EventEmitter () {};\n\n  /**\n   * Adds a listener\n   *\n   * @api public\n   */\n\n  EventEmitter.prototype.on = function (name, fn) {\n    if (!this.$events) {\n      this.$events = {};\n    }\n\n    if (!this.$events[name]) {\n      this.$events[name] = fn;\n    } else if (io.util.isArray(this.$events[name])) {\n      this.$events[name].push(fn);\n    } else {\n      this.$events[name] = [this.$events[name], fn];\n    }\n\n    return this;\n  };\n\n  EventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n  /**\n   * Adds a volatile listener.\n   *\n   * @api public\n   */\n\n  EventEmitter.prototype.once = function (name, fn) {\n    var self = this;\n\n    function on () {\n      self.removeListener(name, on);\n      fn.apply(this, arguments);\n    };\n\n    on.listener = fn;\n    this.on(name, on);\n\n    return this;\n  };\n\n  /**\n   * Removes a listener.\n   *\n   * @api public\n   */\n\n  EventEmitter.prototype.removeListener = function (name, fn) {\n    if (this.$events && this.$events[name]) {\n      var list = this.$events[name];\n\n      if (io.util.isArray(list)) {\n        var pos = -1;\n\n        for (var i = 0, l = list.length; i < l; i++) {\n          if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {\n            pos = i;\n            break;\n          }\n        }\n\n        if (pos < 0) {\n          return this;\n        }\n\n        list.splice(pos, 1);\n\n        if (!list.length) {\n          delete this.$events[name];\n        }\n      } else if (list === fn || (list.listener && list.listener === fn)) {\n        delete this.$events[name];\n      }\n    }\n\n    return this;\n  };\n\n  /**\n   * Removes all listeners for an event.\n   *\n   * @api public\n   */\n\n  EventEmitter.prototype.removeAllListeners = function (name) {\n    if (name === undefined) {\n      this.$events = {};\n      return this;\n    }\n\n    if (this.$events && this.$events[name]) {\n      this.$events[name] = null;\n    }\n\n    return this;\n  };\n\n  /**\n   * Gets all listeners for a certain event.\n   *\n   * @api publci\n   */\n\n  EventEmitter.prototype.listeners = function (name) {\n    if (!this.$events) {\n      this.$events = {};\n    }\n\n    if (!this.$events[name]) {\n      this.$events[name] = [];\n    }\n\n    if (!io.util.isArray(this.$events[name])) {\n      this.$events[name] = [this.$events[name]];\n    }\n\n    return this.$events[name];\n  };\n\n  /**\n   * Emits an event.\n   *\n   * @api public\n   */\n\n  EventEmitter.prototype.emit = function (name) {\n    if (!this.$events) {\n      return false;\n    }\n\n    var handler = this.$events[name];\n\n    if (!handler) {\n      return false;\n    }\n\n    var args = Array.prototype.slice.call(arguments, 1);\n\n    if ('function' == typeof handler) {\n      handler.apply(this, args);\n    } else if (io.util.isArray(handler)) {\n      var listeners = handler.slice();\n\n      for (var i = 0, l = listeners.length; i < l; i++) {\n        listeners[i].apply(this, args);\n      }\n    } else {\n      return false;\n    }\n\n    return true;\n  };\n\n})(\n    'undefined' != typeof io ? io : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n);\n\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n/**\n * Based on JSON2 (http://www.JSON.org/js.html).\n */\n\n(function (exports, nativeJSON) {\n  \"use strict\";\n\n  // use native JSON if it's available\n  if (nativeJSON && nativeJSON.parse){\n    return exports.JSON = {\n      parse: nativeJSON.parse\n    , stringify: nativeJSON.stringify\n    }\n  }\n\n  var JSON = exports.JSON = {};\n\n  function f(n) {\n      // Format integers to have at least two digits.\n      return n < 10 ? '0' + n : n;\n  }\n\n  function date(d, key) {\n    return isFinite(d.valueOf()) ?\n        d.getUTCFullYear()     + '-' +\n        f(d.getUTCMonth() + 1) + '-' +\n        f(d.getUTCDate())      + 'T' +\n        f(d.getUTCHours())     + ':' +\n        f(d.getUTCMinutes())   + ':' +\n        f(d.getUTCSeconds())   + 'Z' : null;\n  };\n\n  var cx = /[\\u0000\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g,\n      escapable = /[\\\\\\\"\\x00-\\x1f\\x7f-\\x9f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g,\n      gap,\n      indent,\n      meta = {    // table of character substitutions\n          '\\b': '\\\\b',\n          '\\t': '\\\\t',\n          '\\n': '\\\\n',\n          '\\f': '\\\\f',\n          '\\r': '\\\\r',\n          '\"' : '\\\\\"',\n          '\\\\': '\\\\\\\\'\n      },\n      rep;\n\n\n  function quote(string) {\n\n// If the string contains no control characters, no quote characters, and no\n// backslash characters, then we can safely slap some quotes around it.\n// Otherwise we must also replace the offending characters with safe escape\n// sequences.\n\n      escapable.lastIndex = 0;\n      return escapable.test(string) ? '\"' + string.replace(escapable, function (a) {\n          var c = meta[a];\n          return typeof c === 'string' ? c :\n              '\\\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);\n      }) + '\"' : '\"' + string + '\"';\n  }\n\n\n  function str(key, holder) {\n\n// Produce a string from holder[key].\n\n      var i,          // The loop counter.\n          k,          // The member key.\n          v,          // The member value.\n          length,\n          mind = gap,\n          partial,\n          value = holder[key];\n\n// If the value has a toJSON method, call it to obtain a replacement value.\n\n      if (value instanceof Date) {\n          value = date(key);\n      }\n\n// If we were called with a replacer function, then call the replacer to\n// obtain a replacement value.\n\n      if (typeof rep === 'function') {\n          value = rep.call(holder, key, value);\n      }\n\n// What happens next depends on the value's type.\n\n      switch (typeof value) {\n      case 'string':\n          return quote(value);\n\n      case 'number':\n\n// JSON numbers must be finite. Encode non-finite numbers as null.\n\n          return isFinite(value) ? String(value) : 'null';\n\n      case 'boolean':\n      case 'null':\n\n// If the value is a boolean or null, convert it to a string. Note:\n// typeof null does not produce 'null'. The case is included here in\n// the remote chance that this gets fixed someday.\n\n          return String(value);\n\n// If the type is 'object', we might be dealing with an object or an array or\n// null.\n\n      case 'object':\n\n// Due to a specification blunder in ECMAScript, typeof null is 'object',\n// so watch out for that case.\n\n          if (!value) {\n              return 'null';\n          }\n\n// Make an array to hold the partial results of stringifying this object value.\n\n          gap += indent;\n          partial = [];\n\n// Is the value an array?\n\n          if (Object.prototype.toString.apply(value) === '[object Array]') {\n\n// The value is an array. Stringify every element. Use null as a placeholder\n// for non-JSON values.\n\n              length = value.length;\n              for (i = 0; i < length; i += 1) {\n                  partial[i] = str(i, value) || 'null';\n              }\n\n// Join all of the elements together, separated with commas, and wrap them in\n// brackets.\n\n              v = partial.length === 0 ? '[]' : gap ?\n                  '[\\n' + gap + partial.join(',\\n' + gap) + '\\n' + mind + ']' :\n                  '[' + partial.join(',') + ']';\n              gap = mind;\n              return v;\n          }\n\n// If the replacer is an array, use it to select the members to be stringified.\n\n          if (rep && typeof rep === 'object') {\n              length = rep.length;\n              for (i = 0; i < length; i += 1) {\n                  if (typeof rep[i] === 'string') {\n                      k = rep[i];\n                      v = str(k, value);\n                      if (v) {\n                          partial.push(quote(k) + (gap ? ': ' : ':') + v);\n                      }\n                  }\n              }\n          } else {\n\n// Otherwise, iterate through all of the keys in the object.\n\n              for (k in value) {\n                  if (Object.prototype.hasOwnProperty.call(value, k)) {\n                      v = str(k, value);\n                      if (v) {\n                          partial.push(quote(k) + (gap ? ': ' : ':') + v);\n                      }\n                  }\n              }\n          }\n\n// Join all of the member texts together, separated with commas,\n// and wrap them in braces.\n\n          v = partial.length === 0 ? '{}' : gap ?\n              '{\\n' + gap + partial.join(',\\n' + gap) + '\\n' + mind + '}' :\n              '{' + partial.join(',') + '}';\n          gap = mind;\n          return v;\n      }\n  }\n\n// If the JSON object does not yet have a stringify method, give it one.\n\n  JSON.stringify = function (value, replacer, space) {\n\n// The stringify method takes a value and an optional replacer, and an optional\n// space parameter, and returns a JSON text. The replacer can be a function\n// that can replace values, or an array of strings that will select the keys.\n// A default replacer method can be provided. Use of the space parameter can\n// produce text that is more easily readable.\n\n      var i;\n      gap = '';\n      indent = '';\n\n// If the space parameter is a number, make an indent string containing that\n// many spaces.\n\n      if (typeof space === 'number') {\n          for (i = 0; i < space; i += 1) {\n              indent += ' ';\n          }\n\n// If the space parameter is a string, it will be used as the indent string.\n\n      } else if (typeof space === 'string') {\n          indent = space;\n      }\n\n// If there is a replacer, it must be a function or an array.\n// Otherwise, throw an error.\n\n      rep = replacer;\n      if (replacer && typeof replacer !== 'function' &&\n              (typeof replacer !== 'object' ||\n              typeof replacer.length !== 'number')) {\n          throw new Error('JSON.stringify');\n      }\n\n// Make a fake root object containing our value under the key of ''.\n// Return the result of stringifying the value.\n\n      return str('', {'': value});\n  };\n\n// If the JSON object does not yet have a parse method, give it one.\n\n  JSON.parse = function (text, reviver) {\n  // The parse method takes a text and an optional reviver function, and returns\n  // a JavaScript value if the text is a valid JSON text.\n\n      var j;\n\n      function walk(holder, key) {\n\n  // The walk method is used to recursively walk the resulting structure so\n  // that modifications can be made.\n\n          var k, v, value = holder[key];\n          if (value && typeof value === 'object') {\n              for (k in value) {\n                  if (Object.prototype.hasOwnProperty.call(value, k)) {\n                      v = walk(value, k);\n                      if (v !== undefined) {\n                          value[k] = v;\n                      } else {\n                          delete value[k];\n                      }\n                  }\n              }\n          }\n          return reviver.call(holder, key, value);\n      }\n\n\n  // Parsing happens in four stages. In the first stage, we replace certain\n  // Unicode characters with escape sequences. JavaScript handles many characters\n  // incorrectly, either silently deleting them, or treating them as line endings.\n\n      text = String(text);\n      cx.lastIndex = 0;\n      if (cx.test(text)) {\n          text = text.replace(cx, function (a) {\n              return '\\\\u' +\n                  ('0000' + a.charCodeAt(0).toString(16)).slice(-4);\n          });\n      }\n\n  // In the second stage, we run the text against regular expressions that look\n  // for non-JSON patterns. We are especially concerned with '()' and 'new'\n  // because they can cause invocation, and '=' because it can cause mutation.\n  // But just to be safe, we want to reject all unexpected forms.\n\n  // We split the second stage into 4 regexp operations in order to work around\n  // crippling inefficiencies in IE's and Safari's regexp engines. First we\n  // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we\n  // replace all simple value tokens with ']' characters. Third, we delete all\n  // open brackets that follow a colon or comma or that begin the text. Finally,\n  // we look to see that the remaining characters are only whitespace or ']' or\n  // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.\n\n      if (/^[\\],:{}\\s]*$/\n              .test(text.replace(/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')\n                  .replace(/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g, ']')\n                  .replace(/(?:^|:|,)(?:\\s*\\[)+/g, ''))) {\n\n  // In the third stage we use the eval function to compile the text into a\n  // JavaScript structure. The '{' operator is subject to a syntactic ambiguity\n  // in JavaScript: it can begin a block or an object literal. We wrap the text\n  // in parens to eliminate the ambiguity.\n\n          j = eval('(' + text + ')');\n\n  // In the optional fourth stage, we recursively walk the new structure, passing\n  // each name/value pair to a reviver function for possible transformation.\n\n          return typeof reviver === 'function' ?\n              walk({'': j}, '') : j;\n      }\n\n  // If the text is not JSON parseable, then a SyntaxError is thrown.\n\n      throw new SyntaxError('JSON.parse');\n  };\n\n})(\n    'undefined' != typeof io ? io : module.exports\n  , typeof JSON !== 'undefined' ? JSON : undefined\n);\n\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io) {\n\n  /**\n   * Parser namespace.\n   *\n   * @namespace\n   */\n\n  var parser = exports.parser = {};\n\n  /**\n   * Packet types.\n   */\n\n  var packets = parser.packets = [\n      'disconnect'\n    , 'connect'\n    , 'heartbeat'\n    , 'message'\n    , 'json'\n    , 'event'\n    , 'ack'\n    , 'error'\n    , 'noop'\n  ];\n\n  /**\n   * Errors reasons.\n   */\n\n  var reasons = parser.reasons = [\n      'transport not supported'\n    , 'client not handshaken'\n    , 'unauthorized'\n  ];\n\n  /**\n   * Errors advice.\n   */\n\n  var advice = parser.advice = [\n      'reconnect'\n  ];\n\n  /**\n   * Shortcuts.\n   */\n\n  var JSON = io.JSON\n    , indexOf = io.util.indexOf;\n\n  /**\n   * Encodes a packet.\n   *\n   * @api private\n   */\n\n  parser.encodePacket = function (packet) {\n    var type = indexOf(packets, packet.type)\n      , id = packet.id || ''\n      , endpoint = packet.endpoint || ''\n      , ack = packet.ack\n      , data = null;\n\n    switch (packet.type) {\n      case 'error':\n        var reason = packet.reason ? indexOf(reasons, packet.reason) : ''\n          , adv = packet.advice ? indexOf(advice, packet.advice) : '';\n\n        if (reason !== '' || adv !== '')\n          data = reason + (adv !== '' ? ('+' + adv) : '');\n\n        break;\n\n      case 'message':\n        if (packet.data !== '')\n          data = packet.data;\n        break;\n\n      case 'event':\n        var ev = { name: packet.name };\n\n        if (packet.args && packet.args.length) {\n          ev.args = packet.args;\n        }\n\n        data = JSON.stringify(ev);\n        break;\n\n      case 'json':\n        data = JSON.stringify(packet.data);\n        break;\n\n      case 'connect':\n        if (packet.qs)\n          data = packet.qs;\n        break;\n\n      case 'ack':\n        data = packet.ackId\n          + (packet.args && packet.args.length\n              ? '+' + JSON.stringify(packet.args) : '');\n        break;\n    }\n\n    // construct packet with required fragments\n    var encoded = [\n        type\n      , id + (ack == 'data' ? '+' : '')\n      , endpoint\n    ];\n\n    // data fragment is optional\n    if (data !== null && data !== undefined)\n      encoded.push(data);\n\n    return encoded.join(':');\n  };\n\n  /**\n   * Encodes multiple messages (payload).\n   *\n   * @param {Array} messages\n   * @api private\n   */\n\n  parser.encodePayload = function (packets) {\n    var decoded = '';\n\n    if (packets.length == 1)\n      return packets[0];\n\n    for (var i = 0, l = packets.length; i < l; i++) {\n      var packet = packets[i];\n      decoded += '\\ufffd' + packet.length + '\\ufffd' + packets[i];\n    }\n\n    return decoded;\n  };\n\n  /**\n   * Decodes a packet\n   *\n   * @api private\n   */\n\n  var regexp = /([^:]+):([0-9]+)?(\\+)?:([^:]+)?:?([\\s\\S]*)?/;\n\n  parser.decodePacket = function (data) {\n    var pieces = data.match(regexp);\n\n    if (!pieces) return {};\n\n    var id = pieces[2] || ''\n      , data = pieces[5] || ''\n      , packet = {\n            type: packets[pieces[1]]\n          , endpoint: pieces[4] || ''\n        };\n\n    // whether we need to acknowledge the packet\n    if (id) {\n      packet.id = id;\n      if (pieces[3])\n        packet.ack = 'data';\n      else\n        packet.ack = true;\n    }\n\n    // handle different packet types\n    switch (packet.type) {\n      case 'error':\n        var pieces = data.split('+');\n        packet.reason = reasons[pieces[0]] || '';\n        packet.advice = advice[pieces[1]] || '';\n        break;\n\n      case 'message':\n        packet.data = data || '';\n        break;\n\n      case 'event':\n        try {\n          var opts = JSON.parse(data);\n          packet.name = opts.name;\n          packet.args = opts.args;\n        } catch (e) { }\n\n        packet.args = packet.args || [];\n        break;\n\n      case 'json':\n        try {\n          packet.data = JSON.parse(data);\n        } catch (e) { }\n        break;\n\n      case 'connect':\n        packet.qs = data || '';\n        break;\n\n      case 'ack':\n        var pieces = data.match(/^([0-9]+)(\\+)?(.*)/);\n        if (pieces) {\n          packet.ackId = pieces[1];\n          packet.args = [];\n\n          if (pieces[3]) {\n            try {\n              packet.args = pieces[3] ? JSON.parse(pieces[3]) : [];\n            } catch (e) { }\n          }\n        }\n        break;\n\n      case 'disconnect':\n      case 'heartbeat':\n        break;\n    };\n\n    return packet;\n  };\n\n  /**\n   * Decodes data payload. Detects multiple messages\n   *\n   * @return {Array} messages\n   * @api public\n   */\n\n  parser.decodePayload = function (data) {\n    // IE doesn't like data[i] for unicode chars, charAt works fine\n    if (data.charAt(0) == '\\ufffd') {\n      var ret = [];\n\n      for (var i = 1, length = ''; i < data.length; i++) {\n        if (data.charAt(i) == '\\ufffd') {\n          ret.push(parser.decodePacket(data.substr(i + 1).substr(0, length)));\n          i += Number(length) + 1;\n          length = '';\n        } else {\n          length += data.charAt(i);\n        }\n      }\n\n      return ret;\n    } else {\n      return [parser.decodePacket(data)];\n    }\n  };\n\n})(\n    'undefined' != typeof io ? io : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n);\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io) {\n\n  /**\n   * Expose constructor.\n   */\n\n  exports.Transport = Transport;\n\n  /**\n   * This is the transport template for all supported transport methods.\n   *\n   * @constructor\n   * @api public\n   */\n\n  function Transport (socket, sessid) {\n    this.socket = socket;\n    this.sessid = sessid;\n  };\n\n  /**\n   * Apply EventEmitter mixin.\n   */\n\n  io.util.mixin(Transport, io.EventEmitter);\n\n\n  /**\n   * Indicates whether heartbeats is enabled for this transport\n   *\n   * @api private\n   */\n\n  Transport.prototype.heartbeats = function () {\n    return true;\n  }\n\n  /**\n   * Handles the response from the server. When a new response is received\n   * it will automatically update the timeout, decode the message and\n   * forwards the response to the onMessage function for further processing.\n   *\n   * @param {String} data Response from the server.\n   * @api private\n   */\n\n  Transport.prototype.onData = function (data) {\n    this.clearCloseTimeout();\n\n    // If the connection in currently open (or in a reopening state) reset the close\n    // timeout since we have just received data. This check is necessary so\n    // that we don't reset the timeout on an explicitly disconnected connection.\n    if (this.socket.connected || this.socket.connecting || this.socket.reconnecting) {\n      this.setCloseTimeout();\n    }\n\n    if (data !== '') {\n      // todo: we should only do decodePayload for xhr transports\n      var msgs = io.parser.decodePayload(data);\n\n      if (msgs && msgs.length) {\n        for (var i = 0, l = msgs.length; i < l; i++) {\n          this.onPacket(msgs[i]);\n        }\n      }\n    }\n\n    return this;\n  };\n\n  /**\n   * Handles packets.\n   *\n   * @api private\n   */\n\n  Transport.prototype.onPacket = function (packet) {\n    this.socket.setHeartbeatTimeout();\n\n    if (packet.type == 'heartbeat') {\n      return this.onHeartbeat();\n    }\n\n    if (packet.type == 'connect' && packet.endpoint == '') {\n      this.onConnect();\n    }\n\n    if (packet.type == 'error' && packet.advice == 'reconnect') {\n      this.isOpen = false;\n    }\n\n    this.socket.onPacket(packet);\n\n    return this;\n  };\n\n  /**\n   * Sets close timeout\n   *\n   * @api private\n   */\n\n  Transport.prototype.setCloseTimeout = function () {\n    if (!this.closeTimeout) {\n      var self = this;\n\n      this.closeTimeout = setTimeout(function () {\n        self.onDisconnect();\n      }, this.socket.closeTimeout);\n    }\n  };\n\n  /**\n   * Called when transport disconnects.\n   *\n   * @api private\n   */\n\n  Transport.prototype.onDisconnect = function () {\n    if (this.isOpen) this.close();\n    this.clearTimeouts();\n    this.socket.onDisconnect();\n    return this;\n  };\n\n  /**\n   * Called when transport connects\n   *\n   * @api private\n   */\n\n  Transport.prototype.onConnect = function () {\n    this.socket.onConnect();\n    return this;\n  }\n\n  /**\n   * Clears close timeout\n   *\n   * @api private\n   */\n\n  Transport.prototype.clearCloseTimeout = function () {\n    if (this.closeTimeout) {\n      clearTimeout(this.closeTimeout);\n      this.closeTimeout = null;\n    }\n  };\n\n  /**\n   * Clear timeouts\n   *\n   * @api private\n   */\n\n  Transport.prototype.clearTimeouts = function () {\n    this.clearCloseTimeout();\n\n    if (this.reopenTimeout) {\n      clearTimeout(this.reopenTimeout);\n    }\n  };\n\n  /**\n   * Sends a packet\n   *\n   * @param {Object} packet object.\n   * @api private\n   */\n\n  Transport.prototype.packet = function (packet) {\n    this.send(io.parser.encodePacket(packet));\n  };\n\n  /**\n   * Send the received heartbeat message back to server. So the server\n   * knows we are still connected.\n   *\n   * @param {String} heartbeat Heartbeat response from the server.\n   * @api private\n   */\n\n  Transport.prototype.onHeartbeat = function (heartbeat) {\n    this.packet({ type: 'heartbeat' });\n  };\n\n  /**\n   * Called when the transport opens.\n   *\n   * @api private\n   */\n\n  Transport.prototype.onOpen = function () {\n    this.isOpen = true;\n    this.clearCloseTimeout();\n    this.socket.onOpen();\n  };\n\n  /**\n   * Notifies the base when the connection with the Socket.IO server\n   * has been disconnected.\n   *\n   * @api private\n   */\n\n  Transport.prototype.onClose = function () {\n    var self = this;\n\n    /* FIXME: reopen delay causing a infinit loop\n    this.reopenTimeout = setTimeout(function () {\n      self.open();\n    }, this.socket.options['reopen delay']);*/\n\n    this.isOpen = false;\n    this.socket.onClose();\n    this.onDisconnect();\n  };\n\n  /**\n   * Generates a connection url based on the Socket.IO URL Protocol.\n   * See <https://github.com/learnboost/socket.io-node/> for more details.\n   *\n   * @returns {String} Connection url\n   * @api private\n   */\n\n  Transport.prototype.prepareUrl = function () {\n    var options = this.socket.options;\n\n    return this.scheme() + '://'\n      + options.host + ':' + options.port + '/'\n      + options.resource + '/' + io.protocol\n      + '/' + this.name + '/' + this.sessid;\n  };\n\n  /**\n   * Checks if the transport is ready to start a connection.\n   *\n   * @param {Socket} socket The socket instance that needs a transport\n   * @param {Function} fn The callback\n   * @api private\n   */\n\n  Transport.prototype.ready = function (socket, fn) {\n    fn.call(this);\n  };\n})(\n    'undefined' != typeof io ? io : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n);\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io, global) {\n\n  /**\n   * Expose constructor.\n   */\n\n  exports.Socket = Socket;\n\n  /**\n   * Create a new `Socket.IO client` which can establish a persistent\n   * connection with a Socket.IO enabled server.\n   *\n   * @api public\n   */\n\n  function Socket (options) {\n    this.options = {\n        port: 80\n      , secure: false\n      , document: 'document' in global ? document : false\n      , resource: 'socket.io'\n      , transports: io.transports\n      , 'connect timeout': 10000\n      , 'try multiple transports': true\n      , 'reconnect': true\n      , 'reconnection delay': 500\n      , 'reconnection limit': Infinity\n      , 'reopen delay': 3000\n      , 'max reconnection attempts': 10\n      , 'sync disconnect on unload': false\n      , 'auto connect': true\n      , 'flash policy port': 10843\n      , 'manualFlush': false\n    };\n\n    io.util.merge(this.options, options);\n\n    this.connected = false;\n    this.open = false;\n    this.connecting = false;\n    this.reconnecting = false;\n    this.namespaces = {};\n    this.buffer = [];\n    this.doBuffer = false;\n\n    if (this.options['sync disconnect on unload'] &&\n        (!this.isXDomain() || io.util.ua.hasCORS)) {\n      var self = this;\n      io.util.on(global, 'beforeunload', function () {\n        self.disconnectSync();\n      }, false);\n    }\n\n    if (this.options['auto connect']) {\n      this.connect();\n    }\n};\n\n  /**\n   * Apply EventEmitter mixin.\n   */\n\n  io.util.mixin(Socket, io.EventEmitter);\n\n  /**\n   * Returns a namespace listener/emitter for this socket\n   *\n   * @api public\n   */\n\n  Socket.prototype.of = function (name) {\n    if (!this.namespaces[name]) {\n      this.namespaces[name] = new io.SocketNamespace(this, name);\n\n      if (name !== '') {\n        this.namespaces[name].packet({ type: 'connect' });\n      }\n    }\n\n    return this.namespaces[name];\n  };\n\n  /**\n   * Emits the given event to the Socket and all namespaces\n   *\n   * @api private\n   */\n\n  Socket.prototype.publish = function () {\n    this.emit.apply(this, arguments);\n\n    var nsp;\n\n    for (var i in this.namespaces) {\n      if (this.namespaces.hasOwnProperty(i)) {\n        nsp = this.of(i);\n        nsp.$emit.apply(nsp, arguments);\n      }\n    }\n  };\n\n  /**\n   * Performs the handshake\n   *\n   * @api private\n   */\n\n  function empty () { };\n\n  Socket.prototype.handshake = function (fn) {\n    var self = this\n      , options = this.options;\n\n    function complete (data) {\n      if (data instanceof Error) {\n        self.connecting = false;\n        self.onError(data.message);\n      } else {\n        fn.apply(null, data.split(':'));\n      }\n    };\n\n    var url = [\n          'http' + (options.secure ? 's' : '') + ':/'\n        , options.host + ':' + options.port\n        , options.resource\n        , io.protocol\n        , io.util.query(this.options.query, 't=' + +new Date)\n      ].join('/');\n\n    if (this.isXDomain() && !io.util.ua.hasCORS) {\n      var insertAt = document.getElementsByTagName('script')[0]\n        , script = document.createElement('script');\n\n      script.src = url + '&jsonp=' + io.j.length;\n      insertAt.parentNode.insertBefore(script, insertAt);\n\n      io.j.push(function (data) {\n        complete(data);\n        script.parentNode.removeChild(script);\n      });\n    } else {\n      var xhr = io.util.request();\n\n      xhr.open('GET', url, true);\n      if (this.isXDomain()) {\n        xhr.withCredentials = true;\n      }\n      xhr.onreadystatechange = function () {\n        if (xhr.readyState == 4) {\n          xhr.onreadystatechange = empty;\n\n          if (xhr.status == 200) {\n            complete(xhr.responseText);\n          } else if (xhr.status == 403) {\n            self.onError(xhr.responseText);\n          } else {\n            self.connecting = false;\n            !self.reconnecting && self.onError(xhr.responseText);\n          }\n        }\n      };\n      xhr.send(null);\n    }\n  };\n\n  /**\n   * Find an available transport based on the options supplied in the constructor.\n   *\n   * @api private\n   */\n\n  Socket.prototype.getTransport = function (override) {\n    var transports = override || this.transports, match;\n\n    for (var i = 0, transport; transport = transports[i]; i++) {\n      if (io.Transport[transport]\n        && io.Transport[transport].check(this)\n        && (!this.isXDomain() || io.Transport[transport].xdomainCheck(this))) {\n        return new io.Transport[transport](this, this.sessionid);\n      }\n    }\n\n    return null;\n  };\n\n  /**\n   * Connects to the server.\n   *\n   * @param {Function} [fn] Callback.\n   * @returns {io.Socket}\n   * @api public\n   */\n\n  Socket.prototype.connect = function (fn) {\n    if (this.connecting) {\n      return this;\n    }\n\n    var self = this;\n    self.connecting = true;\n\n    this.handshake(function (sid, heartbeat, close, transports) {\n      self.sessionid = sid;\n      self.closeTimeout = close * 1000;\n      self.heartbeatTimeout = heartbeat * 1000;\n      if(!self.transports)\n          self.transports = self.origTransports = (transports ? io.util.intersect(\n              transports.split(',')\n            , self.options.transports\n          ) : self.options.transports);\n\n      self.setHeartbeatTimeout();\n\n      function connect (transports){\n        if (self.transport) self.transport.clearTimeouts();\n\n        self.transport = self.getTransport(transports);\n        if (!self.transport) return self.publish('connect_failed');\n\n        // once the transport is ready\n        self.transport.ready(self, function () {\n          self.connecting = true;\n          self.publish('connecting', self.transport.name);\n          self.transport.open();\n\n          if (self.options['connect timeout']) {\n            self.connectTimeoutTimer = setTimeout(function () {\n              if (!self.connected) {\n                self.connecting = false;\n\n                if (self.options['try multiple transports']) {\n                  var remaining = self.transports;\n\n                  while (remaining.length > 0 && remaining.splice(0,1)[0] !=\n                         self.transport.name) {}\n\n                    if (remaining.length){\n                      connect(remaining);\n                    } else {\n                      self.publish('connect_failed');\n                    }\n                }\n              }\n            }, self.options['connect timeout']);\n          }\n        });\n      }\n\n      connect(self.transports);\n\n      self.once('connect', function (){\n        clearTimeout(self.connectTimeoutTimer);\n\n        fn && typeof fn == 'function' && fn();\n      });\n    });\n\n    return this;\n  };\n\n  /**\n   * Clears and sets a new heartbeat timeout using the value given by the\n   * server during the handshake.\n   *\n   * @api private\n   */\n\n  Socket.prototype.setHeartbeatTimeout = function () {\n    clearTimeout(this.heartbeatTimeoutTimer);\n    if(this.transport && !this.transport.heartbeats()) return;\n\n    var self = this;\n    this.heartbeatTimeoutTimer = setTimeout(function () {\n      self.transport.onClose();\n    }, this.heartbeatTimeout);\n  };\n\n  /**\n   * Sends a message.\n   *\n   * @param {Object} data packet.\n   * @returns {io.Socket}\n   * @api public\n   */\n\n  Socket.prototype.packet = function (data) {\n    if (this.connected && !this.doBuffer) {\n      this.transport.packet(data);\n    } else {\n      this.buffer.push(data);\n    }\n\n    return this;\n  };\n\n  /**\n   * Sets buffer state\n   *\n   * @api private\n   */\n\n  Socket.prototype.setBuffer = function (v) {\n    this.doBuffer = v;\n\n    if (!v && this.connected && this.buffer.length) {\n      if (!this.options['manualFlush']) {\n        this.flushBuffer();\n      }\n    }\n  };\n\n  /**\n   * Flushes the buffer data over the wire.\n   * To be invoked manually when 'manualFlush' is set to true.\n   *\n   * @api public\n   */\n\n  Socket.prototype.flushBuffer = function() {\n    this.transport.payload(this.buffer);\n    this.buffer = [];\n  };\n\n\n  /**\n   * Disconnect the established connect.\n   *\n   * @returns {io.Socket}\n   * @api public\n   */\n\n  Socket.prototype.disconnect = function () {\n    if (this.connected || this.connecting) {\n      if (this.open) {\n        this.of('').packet({ type: 'disconnect' });\n      }\n\n      // handle disconnection immediately\n      this.onDisconnect('booted');\n    }\n\n    return this;\n  };\n\n  /**\n   * Disconnects the socket with a sync XHR.\n   *\n   * @api private\n   */\n\n  Socket.prototype.disconnectSync = function () {\n    // ensure disconnection\n    var xhr = io.util.request();\n    var uri = [\n        'http' + (this.options.secure ? 's' : '') + ':/'\n      , this.options.host + ':' + this.options.port\n      , this.options.resource\n      , io.protocol\n      , ''\n      , this.sessionid\n    ].join('/') + '/?disconnect=1';\n\n    xhr.open('GET', uri, false);\n    xhr.send(null);\n\n    // handle disconnection immediately\n    this.onDisconnect('booted');\n  };\n\n  /**\n   * Check if we need to use cross domain enabled transports. Cross domain would\n   * be a different port or different domain name.\n   *\n   * @returns {Boolean}\n   * @api private\n   */\n\n  Socket.prototype.isXDomain = function () {\n\n    var port = global.location.port ||\n      ('https:' == global.location.protocol ? 443 : 80);\n\n    return this.options.host !== global.location.hostname\n      || this.options.port != port;\n  };\n\n  /**\n   * Called upon handshake.\n   *\n   * @api private\n   */\n\n  Socket.prototype.onConnect = function () {\n    if (!this.connected) {\n      this.connected = true;\n      this.connecting = false;\n      if (!this.doBuffer) {\n        // make sure to flush the buffer\n        this.setBuffer(false);\n      }\n      this.emit('connect');\n    }\n  };\n\n  /**\n   * Called when the transport opens\n   *\n   * @api private\n   */\n\n  Socket.prototype.onOpen = function () {\n    this.open = true;\n  };\n\n  /**\n   * Called when the transport closes.\n   *\n   * @api private\n   */\n\n  Socket.prototype.onClose = function () {\n    this.open = false;\n    clearTimeout(this.heartbeatTimeoutTimer);\n  };\n\n  /**\n   * Called when the transport first opens a connection\n   *\n   * @param text\n   */\n\n  Socket.prototype.onPacket = function (packet) {\n    this.of(packet.endpoint).onPacket(packet);\n  };\n\n  /**\n   * Handles an error.\n   *\n   * @api private\n   */\n\n  Socket.prototype.onError = function (err) {\n    if (err && err.advice) {\n      if (err.advice === 'reconnect' && (this.connected || this.connecting)) {\n        this.disconnect();\n        if (this.options.reconnect) {\n          this.reconnect();\n        }\n      }\n    }\n\n    this.publish('error', err && err.reason ? err.reason : err);\n  };\n\n  /**\n   * Called when the transport disconnects.\n   *\n   * @api private\n   */\n\n  Socket.prototype.onDisconnect = function (reason) {\n    var wasConnected = this.connected\n      , wasConnecting = this.connecting;\n\n    this.connected = false;\n    this.connecting = false;\n    this.open = false;\n\n    if (wasConnected || wasConnecting) {\n      this.transport.close();\n      this.transport.clearTimeouts();\n      if (wasConnected) {\n        this.publish('disconnect', reason);\n\n        if ('booted' != reason && this.options.reconnect && !this.reconnecting) {\n          this.reconnect();\n        }\n      }\n    }\n  };\n\n  /**\n   * Called upon reconnection.\n   *\n   * @api private\n   */\n\n  Socket.prototype.reconnect = function () {\n    this.reconnecting = true;\n    this.reconnectionAttempts = 0;\n    this.reconnectionDelay = this.options['reconnection delay'];\n\n    var self = this\n      , maxAttempts = this.options['max reconnection attempts']\n      , tryMultiple = this.options['try multiple transports']\n      , limit = this.options['reconnection limit'];\n\n    function reset () {\n      if (self.connected) {\n        for (var i in self.namespaces) {\n          if (self.namespaces.hasOwnProperty(i) && '' !== i) {\n              self.namespaces[i].packet({ type: 'connect' });\n          }\n        }\n        self.publish('reconnect', self.transport.name, self.reconnectionAttempts);\n      }\n\n      clearTimeout(self.reconnectionTimer);\n\n      self.removeListener('connect_failed', maybeReconnect);\n      self.removeListener('connect', maybeReconnect);\n\n      self.reconnecting = false;\n\n      delete self.reconnectionAttempts;\n      delete self.reconnectionDelay;\n      delete self.reconnectionTimer;\n      delete self.redoTransports;\n\n      self.options['try multiple transports'] = tryMultiple;\n    };\n\n    function maybeReconnect () {\n      if (!self.reconnecting) {\n        return;\n      }\n\n      if (self.connected) {\n        return reset();\n      };\n\n      if (self.connecting && self.reconnecting) {\n        return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);\n      }\n\n      if (self.reconnectionAttempts++ >= maxAttempts) {\n        if (!self.redoTransports) {\n          self.on('connect_failed', maybeReconnect);\n          self.options['try multiple transports'] = true;\n          self.transports = self.origTransports;\n          self.transport = self.getTransport();\n          self.redoTransports = true;\n          self.connect();\n        } else {\n          self.publish('reconnect_failed');\n          reset();\n        }\n      } else {\n        if (self.reconnectionDelay < limit) {\n          self.reconnectionDelay *= 2; // exponential back off\n        }\n\n        self.connect();\n        self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);\n        self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);\n      }\n    };\n\n    this.options['try multiple transports'] = false;\n    this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);\n\n    this.on('connect', maybeReconnect);\n  };\n\n})(\n    'undefined' != typeof io ? io : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n  , this\n);\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io) {\n\n  /**\n   * Expose constructor.\n   */\n\n  exports.SocketNamespace = SocketNamespace;\n\n  /**\n   * Socket namespace constructor.\n   *\n   * @constructor\n   * @api public\n   */\n\n  function SocketNamespace (socket, name) {\n    this.socket = socket;\n    this.name = name || '';\n    this.flags = {};\n    this.json = new Flag(this, 'json');\n    this.ackPackets = 0;\n    this.acks = {};\n  };\n\n  /**\n   * Apply EventEmitter mixin.\n   */\n\n  io.util.mixin(SocketNamespace, io.EventEmitter);\n\n  /**\n   * Copies emit since we override it\n   *\n   * @api private\n   */\n\n  SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit;\n\n  /**\n   * Creates a new namespace, by proxying the request to the socket. This\n   * allows us to use the synax as we do on the server.\n   *\n   * @api public\n   */\n\n  SocketNamespace.prototype.of = function () {\n    return this.socket.of.apply(this.socket, arguments);\n  };\n\n  /**\n   * Sends a packet.\n   *\n   * @api private\n   */\n\n  SocketNamespace.prototype.packet = function (packet) {\n    packet.endpoint = this.name;\n    this.socket.packet(packet);\n    this.flags = {};\n    return this;\n  };\n\n  /**\n   * Sends a message\n   *\n   * @api public\n   */\n\n  SocketNamespace.prototype.send = function (data, fn) {\n    var packet = {\n        type: this.flags.json ? 'json' : 'message'\n      , data: data\n    };\n\n    if ('function' == typeof fn) {\n      packet.id = ++this.ackPackets;\n      packet.ack = true;\n      this.acks[packet.id] = fn;\n    }\n\n    return this.packet(packet);\n  };\n\n  /**\n   * Emits an event\n   *\n   * @api public\n   */\n\n  SocketNamespace.prototype.emit = function (name) {\n    var args = Array.prototype.slice.call(arguments, 1)\n      , lastArg = args[args.length - 1]\n      , packet = {\n            type: 'event'\n          , name: name\n        };\n\n    if ('function' == typeof lastArg) {\n      packet.id = ++this.ackPackets;\n      packet.ack = 'data';\n      this.acks[packet.id] = lastArg;\n      args = args.slice(0, args.length - 1);\n    }\n\n    packet.args = args;\n\n    return this.packet(packet);\n  };\n\n  /**\n   * Disconnects the namespace\n   *\n   * @api private\n   */\n\n  SocketNamespace.prototype.disconnect = function () {\n    if (this.name === '') {\n      this.socket.disconnect();\n    } else {\n      this.packet({ type: 'disconnect' });\n      this.$emit('disconnect');\n    }\n\n    return this;\n  };\n\n  /**\n   * Handles a packet\n   *\n   * @api private\n   */\n\n  SocketNamespace.prototype.onPacket = function (packet) {\n    var self = this;\n\n    function ack () {\n      self.packet({\n          type: 'ack'\n        , args: io.util.toArray(arguments)\n        , ackId: packet.id\n      });\n    };\n\n    switch (packet.type) {\n      case 'connect':\n        this.$emit('connect');\n        break;\n\n      case 'disconnect':\n        if (this.name === '') {\n          this.socket.onDisconnect(packet.reason || 'booted');\n        } else {\n          this.$emit('disconnect', packet.reason);\n        }\n        break;\n\n      case 'message':\n      case 'json':\n        var params = ['message', packet.data];\n\n        if (packet.ack == 'data') {\n          params.push(ack);\n        } else if (packet.ack) {\n          this.packet({ type: 'ack', ackId: packet.id });\n        }\n\n        this.$emit.apply(this, params);\n        break;\n\n      case 'event':\n        var params = [packet.name].concat(packet.args);\n\n        if (packet.ack == 'data')\n          params.push(ack);\n\n        this.$emit.apply(this, params);\n        break;\n\n      case 'ack':\n        if (this.acks[packet.ackId]) {\n          this.acks[packet.ackId].apply(this, packet.args);\n          delete this.acks[packet.ackId];\n        }\n        break;\n\n      case 'error':\n        if (packet.advice){\n          this.socket.onError(packet);\n        } else {\n          if (packet.reason == 'unauthorized') {\n            this.$emit('connect_failed', packet.reason);\n          } else {\n            this.$emit('error', packet.reason);\n          }\n        }\n        break;\n    }\n  };\n\n  /**\n   * Flag interface.\n   *\n   * @api private\n   */\n\n  function Flag (nsp, name) {\n    this.namespace = nsp;\n    this.name = name;\n  };\n\n  /**\n   * Send a message\n   *\n   * @api public\n   */\n\n  Flag.prototype.send = function () {\n    this.namespace.flags[this.name] = true;\n    this.namespace.send.apply(this.namespace, arguments);\n  };\n\n  /**\n   * Emit an event\n   *\n   * @api public\n   */\n\n  Flag.prototype.emit = function () {\n    this.namespace.flags[this.name] = true;\n    this.namespace.emit.apply(this.namespace, arguments);\n  };\n\n})(\n    'undefined' != typeof io ? io : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n);\n\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io, global) {\n\n  /**\n   * Expose constructor.\n   */\n\n  exports.websocket = WS;\n\n  /**\n   * The WebSocket transport uses the HTML5 WebSocket API to establish an\n   * persistent connection with the Socket.IO server. This transport will also\n   * be inherited by the FlashSocket fallback as it provides a API compatible\n   * polyfill for the WebSockets.\n   *\n   * @constructor\n   * @extends {io.Transport}\n   * @api public\n   */\n\n  function WS (socket) {\n    io.Transport.apply(this, arguments);\n  };\n\n  /**\n   * Inherits from Transport.\n   */\n\n  io.util.inherit(WS, io.Transport);\n\n  /**\n   * Transport name\n   *\n   * @api public\n   */\n\n  WS.prototype.name = 'websocket';\n\n  /**\n   * Initializes a new `WebSocket` connection with the Socket.IO server. We attach\n   * all the appropriate listeners to handle the responses from the server.\n   *\n   * @returns {Transport}\n   * @api public\n   */\n\n  WS.prototype.open = function () {\n    var query = io.util.query(this.socket.options.query)\n      , self = this\n      , Socket\n\n\n    if (!Socket) {\n      Socket = global.MozWebSocket || global.WebSocket;\n    }\n\n    this.websocket = new Socket(this.prepareUrl() + query);\n\n    this.websocket.onopen = function () {\n      self.onOpen();\n      self.socket.setBuffer(false);\n    };\n    this.websocket.onmessage = function (ev) {\n      self.onData(ev.data);\n    };\n    this.websocket.onclose = function () {\n      self.onClose();\n      self.socket.setBuffer(true);\n    };\n    this.websocket.onerror = function (e) {\n      self.onError(e);\n    };\n\n    return this;\n  };\n\n  /**\n   * Send a message to the Socket.IO server. The message will automatically be\n   * encoded in the correct message format.\n   *\n   * @returns {Transport}\n   * @api public\n   */\n\n  // Do to a bug in the current IDevices browser, we need to wrap the send in a\n  // setTimeout, when they resume from sleeping the browser will crash if\n  // we don't allow the browser time to detect the socket has been closed\n  if (io.util.ua.iDevice) {\n    WS.prototype.send = function (data) {\n      var self = this;\n      setTimeout(function() {\n         self.websocket.send(data);\n      },0);\n      return this;\n    };\n  } else {\n    WS.prototype.send = function (data) {\n      this.websocket.send(data);\n      return this;\n    };\n  }\n\n  /**\n   * Payload\n   *\n   * @api private\n   */\n\n  WS.prototype.payload = function (arr) {\n    for (var i = 0, l = arr.length; i < l; i++) {\n      this.packet(arr[i]);\n    }\n    return this;\n  };\n\n  /**\n   * Disconnect the established `WebSocket` connection.\n   *\n   * @returns {Transport}\n   * @api public\n   */\n\n  WS.prototype.close = function () {\n    this.websocket.close();\n    return this;\n  };\n\n  /**\n   * Handle the errors that `WebSocket` might be giving when we\n   * are attempting to connect or send messages.\n   *\n   * @param {Error} e The error.\n   * @api private\n   */\n\n  WS.prototype.onError = function (e) {\n    this.socket.onError(e);\n  };\n\n  /**\n   * Returns the appropriate scheme for the URI generation.\n   *\n   * @api private\n   */\n  WS.prototype.scheme = function () {\n    return this.socket.options.secure ? 'wss' : 'ws';\n  };\n\n  /**\n   * Checks if the browser has support for native `WebSockets` and that\n   * it's not the polyfill created for the FlashSocket transport.\n   *\n   * @return {Boolean}\n   * @api public\n   */\n\n  WS.check = function () {\n    return ('WebSocket' in global && !('__addTask' in WebSocket))\n          || 'MozWebSocket' in global;\n  };\n\n  /**\n   * Check if the `WebSocket` transport support cross domain communications.\n   *\n   * @returns {Boolean}\n   * @api public\n   */\n\n  WS.xdomainCheck = function () {\n    return true;\n  };\n\n  /**\n   * Add the transport to your public io.transports array.\n   *\n   * @api private\n   */\n\n  io.transports.push('websocket');\n\n})(\n    'undefined' != typeof io ? io.Transport : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n  , this\n);\n\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io) {\n\n  /**\n   * Expose constructor.\n   */\n\n  exports.flashsocket = Flashsocket;\n\n  /**\n   * The FlashSocket transport. This is a API wrapper for the HTML5 WebSocket\n   * specification. It uses a .swf file to communicate with the server. If you want\n   * to serve the .swf file from a other server than where the Socket.IO script is\n   * coming from you need to use the insecure version of the .swf. More information\n   * about this can be found on the github page.\n   *\n   * @constructor\n   * @extends {io.Transport.websocket}\n   * @api public\n   */\n\n  function Flashsocket () {\n    io.Transport.websocket.apply(this, arguments);\n  };\n\n  /**\n   * Inherits from Transport.\n   */\n\n  io.util.inherit(Flashsocket, io.Transport.websocket);\n\n  /**\n   * Transport name\n   *\n   * @api public\n   */\n\n  Flashsocket.prototype.name = 'flashsocket';\n\n  /**\n   * Disconnect the established `FlashSocket` connection. This is done by adding a\n   * new task to the FlashSocket. The rest will be handled off by the `WebSocket`\n   * transport.\n   *\n   * @returns {Transport}\n   * @api public\n   */\n\n  Flashsocket.prototype.open = function () {\n    var self = this\n      , args = arguments;\n\n    WebSocket.__addTask(function () {\n      io.Transport.websocket.prototype.open.apply(self, args);\n    });\n    return this;\n  };\n\n  /**\n   * Sends a message to the Socket.IO server. This is done by adding a new\n   * task to the FlashSocket. The rest will be handled off by the `WebSocket`\n   * transport.\n   *\n   * @returns {Transport}\n   * @api public\n   */\n\n  Flashsocket.prototype.send = function () {\n    var self = this, args = arguments;\n    WebSocket.__addTask(function () {\n      io.Transport.websocket.prototype.send.apply(self, args);\n    });\n    return this;\n  };\n\n  /**\n   * Disconnects the established `FlashSocket` connection.\n   *\n   * @returns {Transport}\n   * @api public\n   */\n\n  Flashsocket.prototype.close = function () {\n    WebSocket.__tasks.length = 0;\n    io.Transport.websocket.prototype.close.call(this);\n    return this;\n  };\n\n  /**\n   * The WebSocket fall back needs to append the flash container to the body\n   * element, so we need to make sure we have access to it. Or defer the call\n   * until we are sure there is a body element.\n   *\n   * @param {Socket} socket The socket instance that needs a transport\n   * @param {Function} fn The callback\n   * @api private\n   */\n\n  Flashsocket.prototype.ready = function (socket, fn) {\n    function init () {\n      var options = socket.options\n        , port = options['flash policy port']\n        , path = [\n              'http' + (options.secure ? 's' : '') + ':/'\n            , options.host + ':' + options.port\n            , options.resource\n            , 'static/flashsocket'\n            , 'WebSocketMain' + (socket.isXDomain() ? 'Insecure' : '') + '.swf'\n          ];\n\n      // Only start downloading the swf file when the checked that this browser\n      // actually supports it\n      if (!Flashsocket.loaded) {\n        if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') {\n          // Set the correct file based on the XDomain settings\n          WEB_SOCKET_SWF_LOCATION = path.join('/');\n        }\n\n        if (port !== 843) {\n          WebSocket.loadFlashPolicyFile('xmlsocket://' + options.host + ':' + port);\n        }\n\n        WebSocket.__initialize();\n        Flashsocket.loaded = true;\n      }\n\n      fn.call(self);\n    }\n\n    var self = this;\n    if (document.body) return init();\n\n    io.util.load(init);\n  };\n\n  /**\n   * Check if the FlashSocket transport is supported as it requires that the Adobe\n   * Flash Player plug-in version `10.0.0` or greater is installed. And also check if\n   * the polyfill is correctly loaded.\n   *\n   * @returns {Boolean}\n   * @api public\n   */\n\n  Flashsocket.check = function () {\n    if (\n        typeof WebSocket == 'undefined'\n      || !('__initialize' in WebSocket) || !swfobject\n    ) return false;\n\n    return swfobject.getFlashPlayerVersion().major >= 10;\n  };\n\n  /**\n   * Check if the FlashSocket transport can be used as cross domain / cross origin\n   * transport. Because we can't see which type (secure or insecure) of .swf is used\n   * we will just return true.\n   *\n   * @returns {Boolean}\n   * @api public\n   */\n\n  Flashsocket.xdomainCheck = function () {\n    return true;\n  };\n\n  /**\n   * Disable AUTO_INITIALIZATION\n   */\n\n  if (typeof window != 'undefined') {\n    WEB_SOCKET_DISABLE_AUTO_INITIALIZATION = true;\n  }\n\n  /**\n   * Add the transport to your public io.transports array.\n   *\n   * @api private\n   */\n\n  io.transports.push('flashsocket');\n})(\n    'undefined' != typeof io ? io.Transport : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n);\n/*\tSWFObject v2.2 <http://code.google.com/p/swfobject/>\n\tis released under the MIT License <http://www.opensource.org/licenses/mit-license.php>\n*/\nif ('undefined' != typeof window) {\nvar swfobject=function(){var D=\"undefined\",r=\"object\",S=\"Shockwave Flash\",W=\"ShockwaveFlash.ShockwaveFlash\",q=\"application/x-shockwave-flash\",R=\"SWFObjectExprInst\",x=\"onreadystatechange\",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\\/(\\d+(\\.\\d+)?).*$/,\"$1\")):false,X=!+\"\\v1\",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\\s+(\\S+\\s+\\S+$)/,\"$1\");ag[0]=parseInt(ab.replace(/^(.*)\\..*$/,\"$1\"),10);ag[1]=parseInt(ab.replace(/^.*\\.(.*)\\s.*$/,\"$1\"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,\"$1\"),10):0}}else{if(typeof O[(['Active'].concat('Object').join('X'))]!=D){try{var ad=new window[(['Active'].concat('Object').join('X'))](W);if(ad){ab=ad.GetVariable(\"$version\");if(ab){X=true;ab=ab.split(\" \")[1].split(\",\");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState==\"complete\")||(typeof j.readyState==D&&(j.getElementsByTagName(\"body\")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener(\"DOMContentLoaded\",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState==\"complete\"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll(\"left\")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName(\"body\")[0].appendChild(C(\"span\"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener(\"load\",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener(\"load\",Y,false)}else{if(typeof O.attachEvent!=D){i(O,\"onload\",Y)}else{if(typeof O.onload==\"function\"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName(\"body\")[0];var aa=C(r);aa.setAttribute(\"type\",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable(\"$version\");if(ab){ab=ab.split(\" \")[1].split(\",\");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute(\"width\")||\"0\";ai.height=ae.getAttribute(\"height\")||\"0\";if(ae.getAttribute(\"class\")){ai.styleclass=ae.getAttribute(\"class\")}if(ae.getAttribute(\"align\")){ai.align=ae.getAttribute(\"align\")}var ah={};var X=ae.getElementsByTagName(\"param\");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute(\"name\").toLowerCase()!=\"movie\"){ah[X[ad].getAttribute(\"name\")]=X[ad].getAttribute(\"value\")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName==\"OBJECT\"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F(\"6.0.65\")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName==\"OBJECT\"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width=\"310\"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height=\"137\"}j.title=j.title.slice(0,47)+\" - Flash Player Installation\";var ad=M.ie&&M.win?(['Active'].concat('').join('X')):\"PlugIn\",ac=\"MMredirectURL=\"+O.location.toString().replace(/&/g,\"%26\")+\"&MMplayerType=\"+ad+\"&MMdoctitle=\"+j.title;if(typeof ab.flashvars!=D){ab.flashvars+=\"&\"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C(\"div\");X+=\"SWFObjectNew\";Y.setAttribute(\"id\",X);ae.parentNode.insertBefore(Y,ae);ae.style.display=\"none\";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C(\"div\");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display=\"none\";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C(\"div\");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName==\"PARAM\")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah=\"\";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()==\"data\"){ag.movie=ai[ae]}else{if(ae.toLowerCase()==\"styleclass\"){ah+=' class=\"'+ai[ae]+'\"'}else{if(ae.toLowerCase()!=\"classid\"){ah+=\" \"+ae+'=\"'+ai[ae]+'\"'}}}}}var af=\"\";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name=\"'+ad+'\" value=\"'+ag[ad]+'\" />'}}aa.outerHTML='<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"'+ah+\">\"+af+\"</object>\";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute(\"type\",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()==\"styleclass\"){Z.setAttribute(\"class\",ai[ac])}else{if(ac.toLowerCase()!=\"classid\"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!=\"movie\"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C(\"param\");aa.setAttribute(\"name\",X);aa.setAttribute(\"value\",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName==\"OBJECT\"){if(M.ie&&M.win){X.style.display=\"none\";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]==\"function\"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(\".\");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName(\"head\")[0];if(!aa){return}var X=(ad&&typeof ad==\"string\")?ad:\"screen\";if(ab){n=null;G=null}if(!n||G!=X){var Z=C(\"style\");Z.setAttribute(\"type\",\"text/css\");Z.setAttribute(\"media\",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+\" {\"+Y+\"}\"))}}}function w(Z,X){if(!m){return}var Y=X?\"visible\":\"hidden\";if(J&&c(Z)){c(Z).style.visibility=Y}else{v(\"#\"+Z,\"visibility:\"+Y)}}function L(Y){var Z=/[\\\\\\\"<>\\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent(\"onunload\",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+=\"\";ag+=\"\";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+=\"&\"+ai+\"=\"+Z[ai]}else{am.flashvars=ai+\"=\"+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\\?/.test(Z)){Z=Z.split(\"?\")[1]}if(aa==null){return L(Z)}var Y=Z.split(\"&\");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf(\"=\"))==aa){return L(Y[X].substring((Y[X].indexOf(\"=\")+1)))}}}return\"\"},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display=\"block\"}}if(E){E(B)}}a=false}}}}();\n}\n// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>\n// License: New BSD License\n// Reference: http://dev.w3.org/html5/websockets/\n// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol\n\n(function() {\n\n  if ('undefined' == typeof window || window.WebSocket) return;\n\n  var console = window.console;\n  if (!console || !console.log || !console.error) {\n    console = {log: function(){ }, error: function(){ }};\n  }\n\n  if (!swfobject.hasFlashPlayerVersion(\"10.0.0\")) {\n    console.error(\"Flash Player >= 10.0.0 is required.\");\n    return;\n  }\n  if (location.protocol == \"file:\") {\n    console.error(\n      \"WARNING: web-socket-js doesn't work in file:///... URL \" +\n      \"unless you set Flash Security Settings properly. \" +\n      \"Open the page via Web server i.e. http://...\");\n  }\n\n  /**\n   * This class represents a faux web socket.\n   * @param {string} url\n   * @param {array or string} protocols\n   * @param {string} proxyHost\n   * @param {int} proxyPort\n   * @param {string} headers\n   */\n  WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {\n    var self = this;\n    self.__id = WebSocket.__nextId++;\n    WebSocket.__instances[self.__id] = self;\n    self.readyState = WebSocket.CONNECTING;\n    self.bufferedAmount = 0;\n    self.__events = {};\n    if (!protocols) {\n      protocols = [];\n    } else if (typeof protocols == \"string\") {\n      protocols = [protocols];\n    }\n    // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.\n    // Otherwise, when onopen fires immediately, onopen is called before it is set.\n    setTimeout(function() {\n      WebSocket.__addTask(function() {\n        WebSocket.__flash.create(\n            self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);\n      });\n    }, 0);\n  };\n\n  /**\n   * Send data to the web socket.\n   * @param {string} data  The data to send to the socket.\n   * @return {boolean}  True for success, false for failure.\n   */\n  WebSocket.prototype.send = function(data) {\n    if (this.readyState == WebSocket.CONNECTING) {\n      throw \"INVALID_STATE_ERR: Web Socket connection has not been established\";\n    }\n    // We use encodeURIComponent() here, because FABridge doesn't work if\n    // the argument includes some characters. We don't use escape() here\n    // because of this:\n    // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions\n    // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't\n    // preserve all Unicode characters either e.g. \"\\uffff\" in Firefox.\n    // Note by wtritch: Hopefully this will not be necessary using ExternalInterface.  Will require\n    // additional testing.\n    var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));\n    if (result < 0) { // success\n      return true;\n    } else {\n      this.bufferedAmount += result;\n      return false;\n    }\n  };\n\n  /**\n   * Close this web socket gracefully.\n   */\n  WebSocket.prototype.close = function() {\n    if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {\n      return;\n    }\n    this.readyState = WebSocket.CLOSING;\n    WebSocket.__flash.close(this.__id);\n  };\n\n  /**\n   * Implementation of {@link <a href=\"http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration\">DOM 2 EventTarget Interface</a>}\n   *\n   * @param {string} type\n   * @param {function} listener\n   * @param {boolean} useCapture\n   * @return void\n   */\n  WebSocket.prototype.addEventListener = function(type, listener, useCapture) {\n    if (!(type in this.__events)) {\n      this.__events[type] = [];\n    }\n    this.__events[type].push(listener);\n  };\n\n  /**\n   * Implementation of {@link <a href=\"http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration\">DOM 2 EventTarget Interface</a>}\n   *\n   * @param {string} type\n   * @param {function} listener\n   * @param {boolean} useCapture\n   * @return void\n   */\n  WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {\n    if (!(type in this.__events)) return;\n    var events = this.__events[type];\n    for (var i = events.length - 1; i >= 0; --i) {\n      if (events[i] === listener) {\n        events.splice(i, 1);\n        break;\n      }\n    }\n  };\n\n  /**\n   * Implementation of {@link <a href=\"http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration\">DOM 2 EventTarget Interface</a>}\n   *\n   * @param {Event} event\n   * @return void\n   */\n  WebSocket.prototype.dispatchEvent = function(event) {\n    var events = this.__events[event.type] || [];\n    for (var i = 0; i < events.length; ++i) {\n      events[i](event);\n    }\n    var handler = this[\"on\" + event.type];\n    if (handler) handler(event);\n  };\n\n  /**\n   * Handles an event from Flash.\n   * @param {Object} flashEvent\n   */\n  WebSocket.prototype.__handleEvent = function(flashEvent) {\n    if (\"readyState\" in flashEvent) {\n      this.readyState = flashEvent.readyState;\n    }\n    if (\"protocol\" in flashEvent) {\n      this.protocol = flashEvent.protocol;\n    }\n\n    var jsEvent;\n    if (flashEvent.type == \"open\" || flashEvent.type == \"error\") {\n      jsEvent = this.__createSimpleEvent(flashEvent.type);\n    } else if (flashEvent.type == \"close\") {\n      // TODO implement jsEvent.wasClean\n      jsEvent = this.__createSimpleEvent(\"close\");\n    } else if (flashEvent.type == \"message\") {\n      var data = decodeURIComponent(flashEvent.message);\n      jsEvent = this.__createMessageEvent(\"message\", data);\n    } else {\n      throw \"unknown event type: \" + flashEvent.type;\n    }\n\n    this.dispatchEvent(jsEvent);\n  };\n\n  WebSocket.prototype.__createSimpleEvent = function(type) {\n    if (document.createEvent && window.Event) {\n      var event = document.createEvent(\"Event\");\n      event.initEvent(type, false, false);\n      return event;\n    } else {\n      return {type: type, bubbles: false, cancelable: false};\n    }\n  };\n\n  WebSocket.prototype.__createMessageEvent = function(type, data) {\n    if (document.createEvent && window.MessageEvent && !window.opera) {\n      var event = document.createEvent(\"MessageEvent\");\n      event.initMessageEvent(\"message\", false, false, data, null, null, window, null);\n      return event;\n    } else {\n      // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.\n      return {type: type, data: data, bubbles: false, cancelable: false};\n    }\n  };\n\n  /**\n   * Define the WebSocket readyState enumeration.\n   */\n  WebSocket.CONNECTING = 0;\n  WebSocket.OPEN = 1;\n  WebSocket.CLOSING = 2;\n  WebSocket.CLOSED = 3;\n\n  WebSocket.__flash = null;\n  WebSocket.__instances = {};\n  WebSocket.__tasks = [];\n  WebSocket.__nextId = 0;\n\n  /**\n   * Load a new flash security policy file.\n   * @param {string} url\n   */\n  WebSocket.loadFlashPolicyFile = function(url){\n    WebSocket.__addTask(function() {\n      WebSocket.__flash.loadManualPolicyFile(url);\n    });\n  };\n\n  /**\n   * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.\n   */\n  WebSocket.__initialize = function() {\n    if (WebSocket.__flash) return;\n\n    if (WebSocket.__swfLocation) {\n      // For backword compatibility.\n      window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;\n    }\n    if (!window.WEB_SOCKET_SWF_LOCATION) {\n      console.error(\"[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf\");\n      return;\n    }\n    var container = document.createElement(\"div\");\n    container.id = \"webSocketContainer\";\n    // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents\n    // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).\n    // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash\n    // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is\n    // the best we can do as far as we know now.\n    container.style.position = \"absolute\";\n    if (WebSocket.__isFlashLite()) {\n      container.style.left = \"0px\";\n      container.style.top = \"0px\";\n    } else {\n      container.style.left = \"-100px\";\n      container.style.top = \"-100px\";\n    }\n    var holder = document.createElement(\"div\");\n    holder.id = \"webSocketFlash\";\n    container.appendChild(holder);\n    document.body.appendChild(container);\n    // See this article for hasPriority:\n    // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html\n    swfobject.embedSWF(\n      WEB_SOCKET_SWF_LOCATION,\n      \"webSocketFlash\",\n      \"1\" /* width */,\n      \"1\" /* height */,\n      \"10.0.0\" /* SWF version */,\n      null,\n      null,\n      {hasPriority: true, swliveconnect : true, allowScriptAccess: \"always\"},\n      null,\n      function(e) {\n        if (!e.success) {\n          console.error(\"[WebSocket] swfobject.embedSWF failed\");\n        }\n      });\n  };\n\n  /**\n   * Called by Flash to notify JS that it's fully loaded and ready\n   * for communication.\n   */\n  WebSocket.__onFlashInitialized = function() {\n    // We need to set a timeout here to avoid round-trip calls\n    // to flash during the initialization process.\n    setTimeout(function() {\n      WebSocket.__flash = document.getElementById(\"webSocketFlash\");\n      WebSocket.__flash.setCallerUrl(location.href);\n      WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);\n      for (var i = 0; i < WebSocket.__tasks.length; ++i) {\n        WebSocket.__tasks[i]();\n      }\n      WebSocket.__tasks = [];\n    }, 0);\n  };\n\n  /**\n   * Called by Flash to notify WebSockets events are fired.\n   */\n  WebSocket.__onFlashEvent = function() {\n    setTimeout(function() {\n      try {\n        // Gets events using receiveEvents() instead of getting it from event object\n        // of Flash event. This is to make sure to keep message order.\n        // It seems sometimes Flash events don't arrive in the same order as they are sent.\n        var events = WebSocket.__flash.receiveEvents();\n        for (var i = 0; i < events.length; ++i) {\n          WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);\n        }\n      } catch (e) {\n        console.error(e);\n      }\n    }, 0);\n    return true;\n  };\n\n  // Called by Flash.\n  WebSocket.__log = function(message) {\n    console.log(decodeURIComponent(message));\n  };\n\n  // Called by Flash.\n  WebSocket.__error = function(message) {\n    console.error(decodeURIComponent(message));\n  };\n\n  WebSocket.__addTask = function(task) {\n    if (WebSocket.__flash) {\n      task();\n    } else {\n      WebSocket.__tasks.push(task);\n    }\n  };\n\n  /**\n   * Test if the browser is running flash lite.\n   * @return {boolean} True if flash lite is running, false otherwise.\n   */\n  WebSocket.__isFlashLite = function() {\n    if (!window.navigator || !window.navigator.mimeTypes) {\n      return false;\n    }\n    var mimeType = window.navigator.mimeTypes[\"application/x-shockwave-flash\"];\n    if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {\n      return false;\n    }\n    return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;\n  };\n\n  if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {\n    if (window.addEventListener) {\n      window.addEventListener(\"load\", function(){\n        WebSocket.__initialize();\n      }, false);\n    } else {\n      window.attachEvent(\"onload\", function(){\n        WebSocket.__initialize();\n      });\n    }\n  }\n\n})();\n\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io, global) {\n\n  /**\n   * Expose constructor.\n   *\n   * @api public\n   */\n\n  exports.XHR = XHR;\n\n  /**\n   * XHR constructor\n   *\n   * @costructor\n   * @api public\n   */\n\n  function XHR (socket) {\n    if (!socket) return;\n\n    io.Transport.apply(this, arguments);\n    this.sendBuffer = [];\n  };\n\n  /**\n   * Inherits from Transport.\n   */\n\n  io.util.inherit(XHR, io.Transport);\n\n  /**\n   * Establish a connection\n   *\n   * @returns {Transport}\n   * @api public\n   */\n\n  XHR.prototype.open = function () {\n    this.socket.setBuffer(false);\n    this.onOpen();\n    this.get();\n\n    // we need to make sure the request succeeds since we have no indication\n    // whether the request opened or not until it succeeded.\n    this.setCloseTimeout();\n\n    return this;\n  };\n\n  /**\n   * Check if we need to send data to the Socket.IO server, if we have data in our\n   * buffer we encode it and forward it to the `post` method.\n   *\n   * @api private\n   */\n\n  XHR.prototype.payload = function (payload) {\n    var msgs = [];\n\n    for (var i = 0, l = payload.length; i < l; i++) {\n      msgs.push(io.parser.encodePacket(payload[i]));\n    }\n\n    this.send(io.parser.encodePayload(msgs));\n  };\n\n  /**\n   * Send data to the Socket.IO server.\n   *\n   * @param data The message\n   * @returns {Transport}\n   * @api public\n   */\n\n  XHR.prototype.send = function (data) {\n    this.post(data);\n    return this;\n  };\n\n  /**\n   * Posts a encoded message to the Socket.IO server.\n   *\n   * @param {String} data A encoded message.\n   * @api private\n   */\n\n  function empty () { };\n\n  XHR.prototype.post = function (data) {\n    var self = this;\n    this.socket.setBuffer(true);\n\n    function stateChange () {\n      if (this.readyState == 4) {\n        this.onreadystatechange = empty;\n        self.posting = false;\n\n        if (this.status == 200){\n          self.socket.setBuffer(false);\n        } else {\n          self.onClose();\n        }\n      }\n    }\n\n    function onload () {\n      this.onload = empty;\n      self.socket.setBuffer(false);\n    };\n\n    this.sendXHR = this.request('POST');\n\n    if (global.XDomainRequest && this.sendXHR instanceof XDomainRequest) {\n      this.sendXHR.onload = this.sendXHR.onerror = onload;\n    } else {\n      this.sendXHR.onreadystatechange = stateChange;\n    }\n\n    this.sendXHR.send(data);\n  };\n\n  /**\n   * Disconnects the established `XHR` connection.\n   *\n   * @returns {Transport}\n   * @api public\n   */\n\n  XHR.prototype.close = function () {\n    this.onClose();\n    return this;\n  };\n\n  /**\n   * Generates a configured XHR request\n   *\n   * @param {String} url The url that needs to be requested.\n   * @param {String} method The method the request should use.\n   * @returns {XMLHttpRequest}\n   * @api private\n   */\n\n  XHR.prototype.request = function (method) {\n    var req = io.util.request(this.socket.isXDomain())\n      , query = io.util.query(this.socket.options.query, 't=' + +new Date);\n\n    req.open(method || 'GET', this.prepareUrl() + query, true);\n\n    if (method == 'POST') {\n      try {\n        if (req.setRequestHeader) {\n          req.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');\n        } else {\n          // XDomainRequest\n          req.contentType = 'text/plain';\n        }\n      } catch (e) {}\n    }\n\n    return req;\n  };\n\n  /**\n   * Returns the scheme to use for the transport URLs.\n   *\n   * @api private\n   */\n\n  XHR.prototype.scheme = function () {\n    return this.socket.options.secure ? 'https' : 'http';\n  };\n\n  /**\n   * Check if the XHR transports are supported\n   *\n   * @param {Boolean} xdomain Check if we support cross domain requests.\n   * @returns {Boolean}\n   * @api public\n   */\n\n  XHR.check = function (socket, xdomain) {\n    try {\n      var request = io.util.request(xdomain),\n          usesXDomReq = (global.XDomainRequest && request instanceof XDomainRequest),\n          socketProtocol = (socket && socket.options && socket.options.secure ? 'https:' : 'http:'),\n          isXProtocol = (socketProtocol != global.location.protocol);\n      if (request && !(usesXDomReq && isXProtocol)) {\n        return true;\n      }\n    } catch(e) {}\n\n    return false;\n  };\n\n  /**\n   * Check if the XHR transport supports cross domain requests.\n   *\n   * @returns {Boolean}\n   * @api public\n   */\n\n  XHR.xdomainCheck = function (socket) {\n    return XHR.check(socket, true);\n  };\n\n})(\n    'undefined' != typeof io ? io.Transport : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n  , this\n);\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io) {\n\n  /**\n   * Expose constructor.\n   */\n\n  exports.htmlfile = HTMLFile;\n\n  /**\n   * The HTMLFile transport creates a `forever iframe` based transport\n   * for Internet Explorer. Regular forever iframe implementations will\n   * continuously trigger the browsers buzy indicators. If the forever iframe\n   * is created inside a `htmlfile` these indicators will not be trigged.\n   *\n   * @constructor\n   * @extends {io.Transport.XHR}\n   * @api public\n   */\n\n  function HTMLFile (socket) {\n    io.Transport.XHR.apply(this, arguments);\n  };\n\n  /**\n   * Inherits from XHR transport.\n   */\n\n  io.util.inherit(HTMLFile, io.Transport.XHR);\n\n  /**\n   * Transport name\n   *\n   * @api public\n   */\n\n  HTMLFile.prototype.name = 'htmlfile';\n\n  /**\n   * Creates a new Ac...eX `htmlfile` with a forever loading iframe\n   * that can be used to listen to messages. Inside the generated\n   * `htmlfile` a reference will be made to the HTMLFile transport.\n   *\n   * @api private\n   */\n\n  HTMLFile.prototype.get = function () {\n    this.doc = new window[(['Active'].concat('Object').join('X'))]('htmlfile');\n    this.doc.open();\n    this.doc.write('<html></html>');\n    this.doc.close();\n    this.doc.parentWindow.s = this;\n\n    var iframeC = this.doc.createElement('div');\n    iframeC.className = 'socketio';\n\n    this.doc.body.appendChild(iframeC);\n    this.iframe = this.doc.createElement('iframe');\n\n    iframeC.appendChild(this.iframe);\n\n    var self = this\n      , query = io.util.query(this.socket.options.query, 't='+ +new Date);\n\n    this.iframe.src = this.prepareUrl() + query;\n\n    io.util.on(window, 'unload', function () {\n      self.destroy();\n    });\n  };\n\n  /**\n   * The Socket.IO server will write script tags inside the forever\n   * iframe, this function will be used as callback for the incoming\n   * information.\n   *\n   * @param {String} data The message\n   * @param {document} doc Reference to the context\n   * @api private\n   */\n\n  HTMLFile.prototype._ = function (data, doc) {\n    this.onData(data);\n    try {\n      var script = doc.getElementsByTagName('script')[0];\n      script.parentNode.removeChild(script);\n    } catch (e) { }\n  };\n\n  /**\n   * Destroy the established connection, iframe and `htmlfile`.\n   * And calls the `CollectGarbage` function of Internet Explorer\n   * to release the memory.\n   *\n   * @api private\n   */\n\n  HTMLFile.prototype.destroy = function () {\n    if (this.iframe){\n      try {\n        this.iframe.src = 'about:blank';\n      } catch(e){}\n\n      this.doc = null;\n      this.iframe.parentNode.removeChild(this.iframe);\n      this.iframe = null;\n\n      CollectGarbage();\n    }\n  };\n\n  /**\n   * Disconnects the established connection.\n   *\n   * @returns {Transport} Chaining.\n   * @api public\n   */\n\n  HTMLFile.prototype.close = function () {\n    this.destroy();\n    return io.Transport.XHR.prototype.close.call(this);\n  };\n\n  /**\n   * Checks if the browser supports this transport. The browser\n   * must have an `Ac...eXObject` implementation.\n   *\n   * @return {Boolean}\n   * @api public\n   */\n\n  HTMLFile.check = function (socket) {\n    if (typeof window != \"undefined\" && (['Active'].concat('Object').join('X')) in window){\n      try {\n        var a = new window[(['Active'].concat('Object').join('X'))]('htmlfile');\n        return a && io.Transport.XHR.check(socket);\n      } catch(e){}\n    }\n    return false;\n  };\n\n  /**\n   * Check if cross domain requests are supported.\n   *\n   * @returns {Boolean}\n   * @api public\n   */\n\n  HTMLFile.xdomainCheck = function () {\n    // we can probably do handling for sub-domains, we should\n    // test that it's cross domain but a subdomain here\n    return false;\n  };\n\n  /**\n   * Add the transport to your public io.transports array.\n   *\n   * @api private\n   */\n\n  io.transports.push('htmlfile');\n\n})(\n    'undefined' != typeof io ? io.Transport : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n);\n\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io, global) {\n\n  /**\n   * Expose constructor.\n   */\n\n  exports['xhr-polling'] = XHRPolling;\n\n  /**\n   * The XHR-polling transport uses long polling XHR requests to create a\n   * \"persistent\" connection with the server.\n   *\n   * @constructor\n   * @api public\n   */\n\n  function XHRPolling () {\n    io.Transport.XHR.apply(this, arguments);\n  };\n\n  /**\n   * Inherits from XHR transport.\n   */\n\n  io.util.inherit(XHRPolling, io.Transport.XHR);\n\n  /**\n   * Merge the properties from XHR transport\n   */\n\n  io.util.merge(XHRPolling, io.Transport.XHR);\n\n  /**\n   * Transport name\n   *\n   * @api public\n   */\n\n  XHRPolling.prototype.name = 'xhr-polling';\n\n  /**\n   * Indicates whether heartbeats is enabled for this transport\n   *\n   * @api private\n   */\n\n  XHRPolling.prototype.heartbeats = function () {\n    return false;\n  };\n\n  /**\n   * Establish a connection, for iPhone and Android this will be done once the page\n   * is loaded.\n   *\n   * @returns {Transport} Chaining.\n   * @api public\n   */\n\n  XHRPolling.prototype.open = function () {\n    var self = this;\n\n    io.Transport.XHR.prototype.open.call(self);\n    return false;\n  };\n\n  /**\n   * Starts a XHR request to wait for incoming messages.\n   *\n   * @api private\n   */\n\n  function empty () {};\n\n  XHRPolling.prototype.get = function () {\n    if (!this.isOpen) return;\n\n    var self = this;\n\n    function stateChange () {\n      if (this.readyState == 4) {\n        this.onreadystatechange = empty;\n\n        if (this.status == 200) {\n          self.onData(this.responseText);\n          self.get();\n        } else {\n          self.onClose();\n        }\n      }\n    };\n\n    function onload () {\n      this.onload = empty;\n      this.onerror = empty;\n      self.onData(this.responseText);\n      self.get();\n    };\n\n    function onerror () {\n      self.onClose();\n    };\n\n    this.xhr = this.request();\n\n    if (global.XDomainRequest && this.xhr instanceof XDomainRequest) {\n      this.xhr.onload = onload;\n      this.xhr.onerror = onerror;\n    } else {\n      this.xhr.onreadystatechange = stateChange;\n    }\n\n    this.xhr.send(null);\n  };\n\n  /**\n   * Handle the unclean close behavior.\n   *\n   * @api private\n   */\n\n  XHRPolling.prototype.onClose = function () {\n    io.Transport.XHR.prototype.onClose.call(this);\n\n    if (this.xhr) {\n      this.xhr.onreadystatechange = this.xhr.onload = this.xhr.onerror = empty;\n      try {\n        this.xhr.abort();\n      } catch(e){}\n      this.xhr = null;\n    }\n  };\n\n  /**\n   * Webkit based browsers show a infinit spinner when you start a XHR request\n   * before the browsers onload event is called so we need to defer opening of\n   * the transport until the onload event is called. Wrapping the cb in our\n   * defer method solve this.\n   *\n   * @param {Socket} socket The socket instance that needs a transport\n   * @param {Function} fn The callback\n   * @api private\n   */\n\n  XHRPolling.prototype.ready = function (socket, fn) {\n    var self = this;\n\n    io.util.defer(function () {\n      fn.call(self);\n    });\n  };\n\n  /**\n   * Add the transport to your public io.transports array.\n   *\n   * @api private\n   */\n\n  io.transports.push('xhr-polling');\n\n})(\n    'undefined' != typeof io ? io.Transport : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n  , this\n);\n\n/**\n * socket.io\n * Copyright(c) 2011 LearnBoost <dev@learnboost.com>\n * MIT Licensed\n */\n\n(function (exports, io, global) {\n  /**\n   * There is a way to hide the loading indicator in Firefox. If you create and\n   * remove a iframe it will stop showing the current loading indicator.\n   * Unfortunately we can't feature detect that and UA sniffing is evil.\n   *\n   * @api private\n   */\n\n  var indicator = global.document && \"MozAppearance\" in\n    global.document.documentElement.style;\n\n  /**\n   * Expose constructor.\n   */\n\n  exports['jsonp-polling'] = JSONPPolling;\n\n  /**\n   * The JSONP transport creates an persistent connection by dynamically\n   * inserting a script tag in the page. This script tag will receive the\n   * information of the Socket.IO server. When new information is received\n   * it creates a new script tag for the new data stream.\n   *\n   * @constructor\n   * @extends {io.Transport.xhr-polling}\n   * @api public\n   */\n\n  function JSONPPolling (socket) {\n    io.Transport['xhr-polling'].apply(this, arguments);\n\n    this.index = io.j.length;\n\n    var self = this;\n\n    io.j.push(function (msg) {\n      self._(msg);\n    });\n  };\n\n  /**\n   * Inherits from XHR polling transport.\n   */\n\n  io.util.inherit(JSONPPolling, io.Transport['xhr-polling']);\n\n  /**\n   * Transport name\n   *\n   * @api public\n   */\n\n  JSONPPolling.prototype.name = 'jsonp-polling';\n\n  /**\n   * Posts a encoded message to the Socket.IO server using an iframe.\n   * The iframe is used because script tags can create POST based requests.\n   * The iframe is positioned outside of the view so the user does not\n   * notice it's existence.\n   *\n   * @param {String} data A encoded message.\n   * @api private\n   */\n\n  JSONPPolling.prototype.post = function (data) {\n    var self = this\n      , query = io.util.query(\n             this.socket.options.query\n          , 't='+ (+new Date) + '&i=' + this.index\n        );\n\n    if (!this.form) {\n      var form = document.createElement('form')\n        , area = document.createElement('textarea')\n        , id = this.iframeId = 'socketio_iframe_' + this.index\n        , iframe;\n\n      form.className = 'socketio';\n      form.style.position = 'absolute';\n      form.style.top = '0px';\n      form.style.left = '0px';\n      form.style.display = 'none';\n      form.target = id;\n      form.method = 'POST';\n      form.setAttribute('accept-charset', 'utf-8');\n      area.name = 'd';\n      form.appendChild(area);\n      document.body.appendChild(form);\n\n      this.form = form;\n      this.area = area;\n    }\n\n    this.form.action = this.prepareUrl() + query;\n\n    function complete () {\n      initIframe();\n      self.socket.setBuffer(false);\n    };\n\n    function initIframe () {\n      if (self.iframe) {\n        self.form.removeChild(self.iframe);\n      }\n\n      try {\n        // ie6 dynamic iframes with target=\"\" support (thanks Chris Lambacher)\n        iframe = document.createElement('<iframe name=\"'+ self.iframeId +'\">');\n      } catch (e) {\n        iframe = document.createElement('iframe');\n        iframe.name = self.iframeId;\n      }\n\n      iframe.id = self.iframeId;\n\n      self.form.appendChild(iframe);\n      self.iframe = iframe;\n    };\n\n    initIframe();\n\n    // we temporarily stringify until we figure out how to prevent\n    // browsers from turning `\\n` into `\\r\\n` in form inputs\n    this.area.value = io.JSON.stringify(data);\n\n    try {\n      this.form.submit();\n    } catch(e) {}\n\n    if (this.iframe.attachEvent) {\n      iframe.onreadystatechange = function () {\n        if (self.iframe.readyState == 'complete') {\n          complete();\n        }\n      };\n    } else {\n      this.iframe.onload = complete;\n    }\n\n    this.socket.setBuffer(true);\n  };\n\n  /**\n   * Creates a new JSONP poll that can be used to listen\n   * for messages from the Socket.IO server.\n   *\n   * @api private\n   */\n\n  JSONPPolling.prototype.get = function () {\n    var self = this\n      , script = document.createElement('script')\n      , query = io.util.query(\n             this.socket.options.query\n          , 't='+ (+new Date) + '&i=' + this.index\n        );\n\n    if (this.script) {\n      this.script.parentNode.removeChild(this.script);\n      this.script = null;\n    }\n\n    script.async = true;\n    script.src = this.prepareUrl() + query;\n    script.onerror = function () {\n      self.onClose();\n    };\n\n    var insertAt = document.getElementsByTagName('script')[0]\n    insertAt.parentNode.insertBefore(script, insertAt);\n    this.script = script;\n\n    if (indicator) {\n      setTimeout(function () {\n        var iframe = document.createElement('iframe');\n        document.body.appendChild(iframe);\n        document.body.removeChild(iframe);\n      }, 100);\n    }\n  };\n\n  /**\n   * Callback function for the incoming message stream from the Socket.IO server.\n   *\n   * @param {String} data The message\n   * @api private\n   */\n\n  JSONPPolling.prototype._ = function (msg) {\n    this.onData(msg);\n    if (this.isOpen) {\n      this.get();\n    }\n    return this;\n  };\n\n  /**\n   * The indicator hack only works after onload\n   *\n   * @param {Socket} socket The socket instance that needs a transport\n   * @param {Function} fn The callback\n   * @api private\n   */\n\n  JSONPPolling.prototype.ready = function (socket, fn) {\n    var self = this;\n    if (!indicator) return fn.call(this);\n\n    io.util.load(function () {\n      fn.call(self);\n    });\n  };\n\n  /**\n   * Checks if browser supports this transport.\n   *\n   * @return {Boolean}\n   * @api public\n   */\n\n  JSONPPolling.check = function () {\n    return 'document' in global;\n  };\n\n  /**\n   * Check if cross domain requests are supported\n   *\n   * @returns {Boolean}\n   * @api public\n   */\n\n  JSONPPolling.xdomainCheck = function () {\n    return true;\n  };\n\n  /**\n   * Add the transport to your public io.transports array.\n   *\n   * @api private\n   */\n\n  io.transports.push('jsonp-polling');\n\n})(\n    'undefined' != typeof io ? io.Transport : module.exports\n  , 'undefined' != typeof io ? io : module.parent.exports\n  , this\n);\n\n})();"
  },
  {
    "path": "res/private/client_cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDnzCCAoegAwIBAgIJAKBuAUr+T7ouMA0GCSqGSIb3DQEBBQUAMGYxCzAJBgNV\nBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHzAdBgNVBAoMFmdpdGh1Yi5j\nb20vaGlkdS9wcHJveHkxHzAdBgNVBAMMFmdpdGh1Yi5jb20vaGlkdS9wcHJveHkw\nHhcNMTUwNTAzMTUxMDM3WhcNMjUwNDMwMTUxMDM3WjBmMQswCQYDVQQGEwJYWDEV\nMBMGA1UEBwwMRGVmYXVsdCBDaXR5MR8wHQYDVQQKDBZnaXRodWIuY29tL2hpZHUv\ncHByb3h5MR8wHQYDVQQDDBZnaXRodWIuY29tL2hpZHUvcHByb3h5MIIBIjANBgkq\nhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0JsXsBi/sfgCRqfeSeff1almRidf0wZn\njt/2htKmjzluJ/f0+irK20AOI4aCtLg+zKopJ8aekwqeo2vm8k9Ht8xWcX6g7I6Y\nZNEDVjrFPlcZd+HFfZ2ItH70YAJQInMHqEWrrNCNR/ndHnlQg+HUrA+od3HjiegQ\nu/OmVVPaSGiytAFc9QzqCuYPtKOZvCn6KBPX3mXbrBnWf0ASpz7ndRPRfYP0MU0u\nt+AfNcj4/lDvSDOKFVbUSe6Prx4cv4HkcQuPngzqHO4el6ABf0ZWJjBwvZFWW14X\nEJ1Jx2ODJmY+Aq3/yq9Z9MjnuVBs7QjoHIqUMuzWeC7MSBZUC5x5SQIDAQABo1Aw\nTjAdBgNVHQ4EFgQUXHNOovxL+NAVXguLVvH+c6Up+YUwHwYDVR0jBBgwFoAUXHNO\novxL+NAVXguLVvH+c6Up+YUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOC\nAQEAm1KOjuRKJRjUgSckYf1CpGrrSK+YRycspPfTg8EZ10TER9ojGj8xF5QYWg50\nDYgFqx5bWLmytIzf+Ob1Ai6w19i+LvuKo2+vAjBm8QfVrqr/wdzDIhBCj+viY/ib\n7OGTEjAPMk149cy/mu+8ta63dGrX15bIBLfS42ntnTlfNVi2UdtSt0HbkBhzu8lo\nwG3HTwWbFLy8TH/mhTuaFE9CqLzYUA+Lyk2/JDKnhHRpkDPgjiZNidQfDP80IMN/\nCAlc/f1kBV1FHOUSQgzaiSKoi3ypsV+fnLNENz+cjBEEgIi3B/daRH+tVqQvh/8R\nLvYTFF4bAcdouYi0y2leXfHhpw==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "res/private/server_key.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA0JsXsBi/sfgCRqfeSeff1almRidf0wZnjt/2htKmjzluJ/f0\n+irK20AOI4aCtLg+zKopJ8aekwqeo2vm8k9Ht8xWcX6g7I6YZNEDVjrFPlcZd+HF\nfZ2ItH70YAJQInMHqEWrrNCNR/ndHnlQg+HUrA+od3HjiegQu/OmVVPaSGiytAFc\n9QzqCuYPtKOZvCn6KBPX3mXbrBnWf0ASpz7ndRPRfYP0MU0ut+AfNcj4/lDvSDOK\nFVbUSe6Prx4cv4HkcQuPngzqHO4el6ABf0ZWJjBwvZFWW14XEJ1Jx2ODJmY+Aq3/\nyq9Z9MjnuVBs7QjoHIqUMuzWeC7MSBZUC5x5SQIDAQABAoIBAQC8EngCze1WOLFk\nnkgs/Z6ydW295hXgna+UApuy5gxAqJiF9GmrehU2IsQch1MkN9B2mRtNvyaMj1CD\nKe8nmw6fyNxOqsnPPKhsjHyjq4zVLZXKnYR+Qh9UC/mq7artxCOtNFMZFVWrBLy0\nks9id6JUFjHerpFkbhNYQM0/tL/h8tEoO4kanUbxq5un8F1Cl2NxRYCgIWvOG5NO\nUZVPtj6oyHUy4OJ33gNkEJ14HYD200F0iw8rhiug7ZKaXd8SSx4yEvOUCSQ+6pV6\nFJOQQLK8gn2V8YKLQNUbdtp4JoQSeaILf4KuWQ423UIW/WXIIoil222hCNnDNRaI\nWW5Pie25AoGBAPev8f6WY3sxpXHpNMrXKj7C0TVf+JQbESS3jMpNm+1iE2uAx99e\n6pXMbWH/7v8WjdLeIMGFNpsI2NCzbQ+cgfrH0SBNiPzelppGZDriqGuy2ezQ3Ypu\npMMr5KyCP+BCoM5PKZQT2qWqiy1tB5mPPMUs45IJbG95G35vU3MmCeP7AoGBANeb\nXwGFImCDFzC53j08GZ+3MhNjLs+6HD75OAdLOmSwJH+NiDal5S2xzDXw+aSwYYv5\nBe8al5Vp+ulZJ2M3qmjlzXp4n8IxooftieDHCoyBILqrmoSHF0aVCyblsecdxQSl\nEL8VgDTFcngwZtJaxZc7Xqe2GmzamW1h330TmhCLAoGAV4Wup12Q7ZlPcv8LDpoV\nbXP95TRybDNcTXMmpt3huXIslpI9DmtFzYUdKcH8O9tGZjrjrD5cW1A2/RhJ83hE\nXc950EZVn7Uv1ngFNuGczeG3K/1qK16JjgXWmja0R5SDqiNC9/ZEDsJCx9x9EQAS\nY0JHb/Uwgftzgavo+wl3+T0CgYAr/eu4p62H+7dznbkWzXh8+ighhI88m0DAKKGh\n+1uCx93qmLo+TEMiu7BrISwOyl5c7Qak7swXFHS5wBMlT2pZ1OnEH3CZcv8ytOj5\nECO6324KKJFykQ3SvP51hVBzU8OrWvK7ymtKWS8uDtIsAZFndhmuJp3lsAS2KM4s\n+x7oWQKBgQCUIcsrr9P5KCs8LTivHSZbw2bxBSAK/FLnRb/Z3iE0F0Cg7sfoqTBc\nmvT0W1Cn0FaXmt3IPk+hgdkKRYS/nocKdH1dAKOiI4sod69D0Ysrp8wRyNyoQRwr\n1OX1MV1VdU5DsC+wIE72U4p6ctAUaAaM4PH5NlHqLrDyHBVvK254Dg==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "res/sjs/req_rewrite.js",
    "content": "\nfunction pproxy_rewrite(req){\n\treq.get=pproxy_params_copy(req.origin.get||{});\n\treq.post=pproxy_params_copy(req.origin.post||{});\n\t\n\t\n\tfor(var k in req.origin.header){\n\t\treq[k]=req.origin.header[k]+\"\";\n\t}\n\t\n\tvar form_get=pproxy_obj_helper(req.get);\n\tvar form_post=pproxy_obj_helper(req.post);\n\t\n\tvar use_file=function(filePath){\n\t\tfilePath=filePath+\"\"\n\t\treq.url=filePath.substr(0,7)==\"http://\"?filePath:(\"http://PPROXY_HOST\"+\"/f/\"+filePath)\n\t}\n\t\n\tCUSTOM_JS\n\treturn req;\n}\n//clone the get and post params\nfunction pproxy_params_copy(obj){\n    var newObj=new Object();\n    for(var k in obj){\n\t\tvar arr=new Array();\n\t\tfor(var i in obj[k]){\n\t\t\tarr[i]=obj[k][i]+\"\";\n\t\t}\n\t\tnewObj[k]=arr;\n    }\n    return newObj\n} \n\nfunction pproxy_obj_helper(values){\n  return {\n      get:function(name){\n    \t  return values[name]\n      },\n      set:function(name,val){\n    \t  values[name]=[val]\n      },\n      add:function(name,val){\n    \t  val=val+\"\"\n    \t  if(typeof values[name]==\"undefined\"){\n    \t\t  values[name]=[val]\n    \t\t  return\n    \t  }\n    \t  if(typeof values[name]!=\"Object\"){\n    \t\t  values[name]=[values[name]+\"\"]\n    \t  }\n          values[name].push(val)\n      },\n      del:function(name){\n    \t  delete values[name]\n      },\n      len:function(name){\n    \t  if(name==undefined){\n    \t    return values.length\n    \t  }else{\n    \t\treturn (values[name]||[]).length \n    \t  }\n      }\n  }\t\n}\n"
  },
  {
    "path": "res/tpl/about.html",
    "content": "<div id=\"bd0\">\n <br/>\n<p class=\"h3\">about</p>\n <p>HTTP protocol analysis tool.</p>\n <p>Based on BS architecture,written by golang.</p>\n <p>Project : <a href=\"https://github.com/hidu/pproxy\" target=\"_blank\">https://github.com/hidu/pproxy</a></p>\n <p>Current Version: <font color=blue>{{.version}}</font></p> \n <p id=\"new_version_slot\"></p>\n <br/>\n\n</div>\n<br/>\n<br/>\n\n<script>\nsetTimeout(function(){\n  $.getScript(\"https://hidu.github.io/pproxy/check.js\");\n},1000);\n</script>\n"
  },
  {
    "path": "res/tpl/config/req_demo.html",
    "content": "<div style=\"color:gray\">\nnote:\n<ol>\n<li>put <font color=blue>//ignore</font> at the first line to ignore the js</li>\n<li>user's js is default,or the global</li>\n\n{{if not .isLogin}}\n<li><a href=\"/login\">login</a> to edit your custom profile</li>\n{{end}}\n\n</ol>\n</div>\n<b>req demo:</b><a href=\"javascript:;\" onclick=\"$('#pre_req_demo').toggle()\">show/hide</a>\n<pre id=\"pre_req_demo\" style=\"display:none\">\nurl : http://www.example.com/album/list?cid=126\nschema : http\nhost : www.example.com\nport : 80\npath : /album/list\nget: {cid:[123]}\npost: {}\nusername : \npassword : \nmethod: GET\n===============================================\n//demo code:<code>\nif(req.host==\"www.baidu.com\"){\n   req.host=\"www.163.com\"\n   req.host_addr=\"127.0.0.0:81\" // send req to 127.0.0.1:81\n   form_get.add(\"a\",\"a\")\n   //form_post.set(\"d\",\"a\")\n}</code>\n//demo 2 <code>\nif(req.host==\"www.hao123.com\"){\n   req.url=\"http://zhida.baidu.com/\"\n}</code>\n//demo 3 <code>\nif(req.host==\"www.hao123.com\"){\n  use_file(\"index.htm\")   //use the static file in dir \"file\"\n}</code>\n</pre>\n<hr/><br/>"
  },
  {
    "path": "res/tpl/config/req_form.html",
    "content": "<span class=\"h6\">req rewrite</span>\n{{range $i,$js:=.jss}}\n<form  method=\"post\" action=\"/config\" autocomplete=\"off\" target=\"ifr_form\">\n<fieldset>\n<legend>{{$js.title}}</legend>\nfunction rewrite(req){\n<textarea style=\"width:95%;height:{{$js.jsHeight}}px\" name=\"js\">{{$js.rewriteJs}}</textarea>\nreturn req;<br/>\n}\n<input type=\"hidden\" name=\"type\" value=\"js\">\n<input type=\"hidden\" name=\"name\" value=\"{{$js.name}}\">\n<div style=\"text-align:center\">\n\n{{if $.isLogin}}\n<input type=\"submit\" class=\"btn btn-primary\" value=\"save\">\n{{else}}\n <div class=\"text-info\">login for submit</div>\n{{end}}\n</div>\n\n<ol>\n{{range $j,$use_file:=$js.use_file}}\n <li>\n    <a href=\"{{$use_file.url}}\" target=\"_blank\">{{$use_file.name}}</a>\n </li>\n{{end}}\n</ol>\n\n</fieldset>\n</form>\n{{end}}"
  },
  {
    "path": "res/tpl/config.html",
    "content": "<script src=\"/res/js/default.js\"></script>\n<style>\n#configTable form{padding:10px;margin-right: 20px}\n</style>\n<br/>\n<div id=\"bd0\">\n<table width=\"100%\" id=\"configTable\">\n<tr><td>{%my_include \"config/req_form.html\"   %}</td></tr>\n<tr><td>{%my_include \"config/req_demo.html\"   %}</td></tr>\n<tr><td>{%my_include \"config/hosts_form.html\" %}</td></tr>\n<tr><td>{%my_include \"config/hosts_demo.html\" %}</td></tr>\n</table>\n\n<iframe name=\"ifr_form\" style=\"display:none;\"></iframe>  \n</div>\n\n<script>\npproxy_tab_sup(\"#bd0\")\n</script>\n"
  },
  {
    "path": "res/tpl/error.html",
    "content": "<div id=\"bd\" style=\"text-align:center;font-size:20px\">\nError:\n<span class=\"text-warning\">{{.error}}</span>\n</div>"
  },
  {
    "path": "res/tpl/file.html",
    "content": "<div id=\"bd\">\n<table class=\"tb_1\">\n<caption>\n<div class=\"left\">\n&nbsp;\n/f/{{.currentDir}} &nbsp;\n<a href=\"/file?op=new&dir={{.currentDir}}\"><img src=\"/res/img/list-add.png\"></a>\n</div>\n</caption>\n<thead>\n <tr>\n  <th width=\"50px\">no</th>\n  <th>\n  {{if .isSubDir}}\n  <span class=\"left\"><a href=\"/file?name={{.currentDir|escape}}/../\">../</a></span>\n  {{end}}\n  Name\n  </th>\n  <th width=\"100px\">Size</th>\n </tr>\n</thead>\n<tbody>\n{{range $k,$file:=.files}}\n<tr>\n  <td class=\"t_c\">{{$k}}</td>\n  <td>\n    <a href=\"{{$file.Link}}\">\n    {{if $file.IsDir}} <img src=\"/res/img/folder.png\">{{else}}<img src=\"/res/img/text.png\">{{end}}\n    {{$file.Name}}\n    </a>\n    &nbsp;\n    {{if $file.IsDir}}\n         <a href=\"/file?op=new&dir={{$file.Name|escape}}\"> <img src=\"/res/img/list-add.png\"></a>\n    {{else}}\n         <a href=\"/f/{{$file.Name}}\" target=\"_blank\"><img src=\"/res/img/view.png\"></a>\n    {{end}}\n  </td>\n  <td>{{$file.Size}}</td>\n</tr>\n{{end}}\n</tbody>\n</table>\n</div>"
  },
  {
    "path": "res/tpl/file_edit.html",
    "content": "<div id=\"bd\">\n<div class=\"h6\">edit file</div>\n<form method=\"post\" action=\"/file\" target=\"ifr_form\">\n<input type=\"hidden\" name=\"op\" value=\"save\">\n\n<input type=\"hidden\" name=\"nameOrigin\" value=\"{{.file.Name|html}}\">\n\n\n<label>fileName:</label>\n<input type=\"text\" name=\"name\" value=\"{{.file.Name|html}}\" class=\"form-control\" style=\"width:300px\" pattern=\"[\\w\\-\\/\\.]{1,15}\" placeholder=\"eg:123.txt or 201408/a.json\" required autofocus title=\"must mutch [\\w\\-\\/]{1,15}\">\n&nbsp;&nbsp;\n<a href=\"/file?name={{.file.Name|escape}}/..\"><img src=\"/res/img/list.png\">go File List</a>\n&nbsp;&nbsp;\n<a href=\"/f/{{.file.Name}}\" target=\"_blank\"><img src=\"/res/img/view.png\">view</a>\n\n<div>\n<textarea style=\"width:95%;\" rows=\"{{.fileContentRows}}\"  name=\"content\">{{.fileContent|html}}</textarea>\n</div>\n<pre>\njs req write:\n<code>use_file(\"{{.file.Name}}\")</code>\n</pre>\n<center><input type=\"submit\" value=\"save it\" class=\"btn btn-primary\"></center>\n</form>\n\n\n</div>\n<script src=\"/res/js/default.js\"></script>\n<script>\npproxy_tab_sup(\"#bd\")\n</script>\n\n<iframe name=\"ifr_form\" style=\"display:none;\"></iframe>  "
  },
  {
    "path": "res/tpl/file_new.html",
    "content": "<div id=\"bd\">\n\n<div class=\"h6\">new file</div>\n<form method=\"post\" action=\"/file\" target=\"ifr_form\">\n<input type=\"hidden\" name=\"op\" value=\"new\">\n\n<input type=\"hidden\" name=\"dir\" value=\"{{.dir}}\">\n\n<label>fileName:</label>\n{{.dir}}/<input type=\"text\" name=\"name\" value=\"\" class=\"form-control\" style=\"width:300px\" pattern=\"[\\w\\-\\/\\.]{1,15}\" placeholder=\"eg:123.txt or 201408/a.json\" required autofocus title=\"must mutch [\\w\\-\\/\\.]{1,15}\">\n\n<div><label>file content:</label></div>\n<div>\n<textarea style=\"width:95%;\" rows=\"10\"  name=\"content\"></textarea>\n</div>\n\n<center><input type=\"submit\" value=\"save it\" class=\"btn btn-primary\"></center>\n</form>\n\n\n</div>\n<script src=\"/res/js/default.js\"></script>\n<script>\npproxy_tab_sup(\"#bd\")\n</script>\n\n<iframe name=\"ifr_form\" style=\"display:none;\"></iframe>  "
  },
  {
    "path": "res/tpl/layout.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<link href=\"/res/img/favicon.ico\"  rel=\"shortcut icon\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"author\" content=\"duwei\">\n<meta name=\"src\" content=\"https://github.com/hidu/pproxy\">\n<title>{{.subTitle}}{{.title}} | pproxy {{.version}}</title>\n<script src=\"/res/js/jquery.js\"></script>\n<link rel=\"stylesheet\" href=\"/res/css/flat.css\">\n<link rel=\"stylesheet\" href=\"/res/css/style.css\">\n<script>var pproxy_version=\"{{.version}}\";</script>\n</head>\n<body>\n<div id=\"nav\">\n<div id=\"menu\">\n       <ul id=\"left_submenu\">\n           <li class=\"border_first\"><a href=\"/\">session</a></li>\n           <li><a href=\"/config\">config</a></li>\n           {{if .isLogin}}\n           <li><a href=\"/file\">file</a></li>\n           {{end}}\n           <li><a href=\"/about\">about</a></li>\n           <li><a href=\"/useage\">useage</a></li>\n       </ul>\n       \n       <div class='right'>\n          <ul>\n            <li  class=\"border_first\">{{.notice}}</li>\n            <li><span id=\"connect_status\">&nbsp;</span></li>\n            <li><span id=\"user_num_online\">{{.userOnlineTotal}}</span> user</li>\n            {{if .isLogin}}\n              <li>{{.user.Name}}</li> \n              <li><a href=\"/logout\">logout</a></li>\n             {{else}}\n              <li><a href=\"/login\">login</a></li>\n            {{end}}\n         </ul> \n         </div>\n       <div class=\"clear\"></div>\n</div>\n</div>\n<div class=\"clear\"></div>\n<div>\n{{.body}}\n</div>\n<div class=\"clear\"></div>\n<div id=\"log_div\"></div>\n</body>\n</html>"
  },
  {
    "path": "res/tpl/login.html",
    "content": "<div id=\"bd0\">\n<br/><br/><br/><br/><br/>\n<div class=\"login-screen\">\n<form method=\"post\" action=\"/login\" target=\"ifr_form\">\n<fieldset>\n<legend>Admin Login</legend>\n         <div class=\"login-form\">\n           <div class=\"form-group\">\n             <input type=\"text\" name=\"name\" placeholder=\"Enter your name\" value=\"\" class=\"form-control\" required>\n           </div>\n\n           <div class=\"form-group\">\n             <input type=\"password\"  name=\"psw\" placeholder=\"Password\" value=\"\" class=\"form-control\">\n           </div>\n           <input type=\"submit\" value=\"Log in\" class=\"btn btn-primary\">\n         </div>\n</fieldset>\n</form>\n</div>\n\n</div>\n<iframe name=\"ifr_form\" style=\"display:none;\"></iframe>  "
  },
  {
    "path": "res/tpl/network.html",
    "content": "<script src=\"/res/js/base64.js\"></script>\n<script src=\"/res/js/socket.io.js\"></script>\n<script src=\"/res/js/session.js\"></script>\n\n<table id=\"network-tb\">\n<tr>\n<td id=\"aside\">\n<div id=\"network_list_div\">\n<div style='margin:3px'>\n<form id=\"network_filter_form\">\n<fieldset>\n<legend>session filter</legend>\n   \t<table width=\"100%\">\n\t  <tr>\n\t  <th width=\"60px\">client:</th>\n\t  <td width=\"40%\"><input type=\"text\" class=\"form-control\" style='width:95%' id='client_ip' name=\"client_ip\" placeholder=\"client ip\"> </td>\n\t  <th width=\"60px\">user:</th>\n\t  <td width=\"40%\"><input type=\"text\" name=\"user\" class=\"form-control\" style=\"width:95%\" placeholder=\"basic auth uname\" title=\"\"></td>\n\t  </tr>\n\t  <tr>\n\t  <th>exclude:</th>\n\t  <td>\n\t\t  <label><input type=\"checkbox\" name=\"hide\" value='image' checked=\"checked\">image</label>\n\t\t  <label><input type=\"checkbox\" name=\"hide\" value='js' checked=\"checked\">js</label>\n\t\t  <label><input type=\"checkbox\" name=\"hide\" value='css' checked=\"checked\">css</label>\n      </td>\n      <td></td>\n\t   <td> <input type=\"text\" name=\"hide_url\" value='' class=\"form-control\" style=\"width:95%\" placeholder=\"any part of url\"></td>\n\t  </tr>\n\t  <tr>\n\t  <th nowrap>url:</th>\n\t  <td colspan=4><input type=\"text\" name=\"url_match\" class=\"form-control\" style=\"width:98%\" placeholder=\"any part of url\"></td>\n\t  </tr>\n  </table>\n  </fieldset>\n</form>\n</div>\n\n<div class=\"panel_1\">\n<div class=\"div_b_i\" style=\"width:20px\">#</div>\nhost\n<div class=\"div_b_i\" style=\"width:30%\"><input type=\"text\" style=\"width:90%\" id=\"net_local_host\"></div>\npath\n<div class=\"div_b_i\" style=\"width:30%\"><input type=\"text\" style=\"width:90%\" id=\"net_local_path\"></div>\n<div class=\"div_b_i right\"  style=\"width:50px\"><a  onclick=\"pporxy_session_clean()\" href=\"javascript:;\" >clean</a></div>\n</div>\t \n <div id=\"div_tb_network_list\">\n\t <table id='tb_network' class=\"tb_1\">\n\t  <thead style='height:1px;overflow: hidden'>\n         <tr>\n             <td width=\"30px\"></td>\n             <td width=\"35%\"></td>\n             <td></td>\n         </tr>\n      </thead>\n\t  <tbody></tbody>\n\t </table>\n </div>\n</div>\n\n</td>\n<td>\n<div id=\"right_content\"></div>\n</td>\n</tr>\n</table>\n"
  },
  {
    "path": "res/tpl/replay.html",
    "content": "<div id=\"bd\">\n<br/>\n<form action=\"/replay\" method=\"post\" id=\"replay_form\" target=\"_blank\" class=\"form_0\" autocomplete=\"off\">\n<div class=\"h4\">replay</div>\n<fieldset>\n<legend>basic</legend>\n<table>\n<tr><th>action url:</th><td><input type=\"text\" name=\"basic_action_url\" value=\"{{.action_url}}\" class=\"form-control\"></td></tr>\n<tr><th>method:</th><td><input type=\"text\" name=\"basic_method\" value=\"{{.req.method}}\" class=\"form-control\" ></td></tr>\n<tr><th>Host:</th><td><input type=\"text\" name=\"basic_host\" value=\"{{.req.host}}\" class=\"form-control\"></td></tr>\n</table>\n<input type=\"hidden\" name=\"basic_RemoteAddr\" value=\"{{.req.client_ip}}\">\n<input type=\"hidden\" name=\"basic_user\" value=\"{{.req.user}}\">\n</fieldset>\n\n<fieldset>\n<legend>header \n<font color=gray>(only use these replay with pproxy)</font> &nbsp;\n<a href=\"#\" onclick=\"$('#tb_header').toggle()\">show/hide</a>\n</legend>\n<table id=\"tb_header\" style=\"display:none\">\n{{range $k,$v:=.req.header}}\n<tr>\n<th>{{$k}}:</th>\n<td>\n  {{range $index,$_v:=$v}}\n    <div><input type=\"text\" name=\"header_{{$k}}\" value=\"{{$_v|html}}\" class=\"form-control\"></div>\n {{end}}\n </td>\n <td class=\"last\">\n <div>\n<a href=\"#\" onclick=\"return add_tr(this,'header_')\">+</a>&nbsp;\n<a href=\"#\" onclick=\"return toggle_able_tr(this)\" title=\"toggle disable\">X</a>\n</div>\n</td>\n </tr>\n{{end}}\n</table>\n</fieldset>\n\n<fieldset>\n<legend>get_params\n<a href=\"#\" onclick=\"return add_tr('#tb_form_get','get_')\">+param</a>\n</legend>\n<table id=\"tb_form_get\">\n{{range $k,$v:=.req.form_get}}\n<tr><th>{{$k}}:</th> <td>\n{{range $index,$_v:=$v}}\n<div><input type=\"text\" name=\"get_{{$k}}\" value=\"{{$_v|html}}\" class=\"form-control\"></div>\n{{end}}\n</td>\n\n<td class=\"last\">\n<div>\n<a href=\"#\" onclick=\"return add_tr(this,'get_')\">+</a>&nbsp;\n<a href=\"#\" onclick=\"return toggle_able_tr(this)\" title=\"toggle disable\">X</a>\n</div>\n</td>\n\n</tr>\n{{end}}\n\n</table>\n</fieldset>\n\n{{if eq .req.method  \"POST\"}}\n<fieldset>\n<legend>post_params\n<a href=\"#\" onclick=\"return add_tr('#tb_form_post','post_')\">+param</a>\n</legend>\n<table id=\"tb_form_post\">\n{{range $k,$v:=.req.form_post}}\n<tr><th>{{$k}}:</th><td> \n{{range $index,$_v:=$v}}\n<div><input type=\"text\" name=\"post_{{$k}}\" value=\"{{$_v|html}}\" class=\"form-control\"></div>\n{{end}}\n</td>\n<td class=\"last\">\n<div>\n<a href=\"#\" onclick=\"return add_tr(this,'post_')\">+</a>&nbsp;\n<a href=\"#\" onclick=\"return toggle_able_tr(this)\" title=\"toggle disable\">X</a>\n</div>\n</td>\n</tr>\n{{end}}\n</table>\n</fieldset>\n{{end}}\n<br/>\n<div style=\"text-align:center;\">\n<input type=\"hidden\" name=\"replay\" id=\"replay\" value=\"pproxy\">\n<input type=\"submit\"  class=\"btn btn-primary\"  value=\"replay with pproxy\" onclick=\"$('#replay').val('pproxy')\">\n<span style=\"margin-left:100px\"></span>\n<input type=\"submit\"  class=\"btn btn-primary\" value=\"replay direct\" onclick=\"$('#replay').val('direct')\">\n</div>\n</form>\n<br/>\n<br/>\n\n</div>\n\n<script>\nfunction toggle_able_tr(obj){\n\t$(obj).parents(\"tr\").find(\"input\").each(function(){\n\t\tif($(this).attr(\"disabled\")){\n\t\t   $(this).removeAttr(\"disabled\");\n\t\t}else{\n\t\t   $(this).attr(\"disabled\",\"disabled\");\n\t\t}\n\t});\n\treturn false;\n}\n\nfunction add_tr(obj,pre){\n   var html=\"<tr>\\\n   <th><input type='text' class='form-control' style='text-align:right;width:80%' onkeyup='tr_val_chnage(this,\\\"\"+pre+\"\\\")' placeholder='param name'>:</th>\\\n   <td><input type='text' disabled=disabled class='form-control' placeholder='param value'></td>\\\n   <td class='last'><a href='#' onclick='$(this).parents(\\\"tr\\\").remove();return flase;'>del</a></td>\\\n   </tr>\";\n   if(typeof obj==\"object\"){\n    $(obj).parents(\"tr\").after(html);\n   }else{\n\t   $(obj).prepend(html)\n   }\n   return false;\n}\n\nfunction tr_val_chnage(obj,pre){\n\tvar next_input=$(obj).parents(\"tr\").find(\"td input\");\n\tvar val=$.trim($(obj).val());\n\tif(val==\"\"){\n\t\tnext_input.attr(\"disabled\",\"disabled\");\n\t}else{\n\t\tnext_input.attr(\"name\",pre+val).removeAttr(\"disabled\");\n\t}\n}\n</script>\n"
  },
  {
    "path": "res/tpl/replay_direct.html",
    "content": "<div id=\"bd\">\n<br/>\n<br/>\n<form action=\"{{.form.basic.action_url}}\" method=\"{{.form.basic.method}}\" class=\"form_0\" id=\"form_replay_direct\">\n<table>\n<caption>{{.form.basic.method}} &nbsp;{{.form.basic.action_url}}</caption>\n{{range $k,$v:=.form.get}}\n\t{{range $_k,$_v:=$v}}\n\t   <tr><th>{{$k}}:</th><td><input type=\"text\" name=\"{{$k}}\" value=\"{{$_v|html}}\"></td></tr>\n\t{{end}}\n{{end}}\n\n{{range $k,$v:=.form.post}}\n\t{{range $_k,$_v:=$v}}\n\t   <tr><th>{{$k}}:</th><td><input type=\"text\" name=\"{{$k}}\" value=\"{{$_v|html}}\"></td></tr>\n\t{{end}}\n{{end}}\n</table>\n\n</form>\n\n<script>\n$(\"#form_replay_direct\").submit();\n</script>\n\n</div>"
  },
  {
    "path": "res/tpl/useage.html",
    "content": "<div id=\"bd0\">\n<br/>\n<p class=\"h4\">Useage</p>\n<p class=\"h6\">1.Client（eg:phone）</p>\n<pre>\nset wifi http proxy:\nproxy host ： <b>{{.pproxy_host}}</b>\nproxy port ： <b>{{.pproxy_port}}</b>\n\n</pre>\n<small>android users can use <b>proxyDroid</b> to manager proxys</small>\n\n<p class=\"h6\">2.Server:user interface</p>\n<pre>\nvisit <a href=\"/\">Session List Page</a> to view all the http request through this proxy.\nin the session filter form, all text input can use<font color=red>|</font> to enter multiple conditions.\neg user:<input type=\"text\" value=\"a|b\" style=\"width:40px\">,it mean user is a or b.\nyou can use <b>replay</b> to replay a request.\n</pre>\n\n<p class=\"h6\">3.Modify Requests</p>\n<div>you can modify http request.GET、POST paramas and http headers.</div>\n<div>pproxy use javascript to achieve it:</div>\n<pre>\nfunction rewrite(req){\n    //you code start<span style=\"color:blue\">\n    if(req.host==\"www.baidu.com\"){\n\t   req.host=\"www.163.com\"\n\t   req.host_addr=\"127.0.0.0:81\" // send req to 127.0.0.1:81\n\t   form_get.add(\"a\",\"a\")\n\t   //form_post.set(\"d\",\"a\")\n\t}\n\t</span>\n    // you code end\n    return req\n}\n</pre>\n<div><b>req object has these attributes</b>(url=http://www.example.com/album/list?cid=126)：</div>\n<pre>\nschema : http\nhost : www.example.com\nport : 80\npath : /album/list\nget: {cid:[123]}\npost: {}\nusername : \npassword : \nmethod: GET\nform_get  : {add:function(k,v){},set:function(k,v){},get:function(k){},len:function(){}} \nform_post : {add:function(k,v){},set:function(k,v){},get:function(k){},len:function(){}}\n\nhost_addr: #the real host you wish，eg 127.0.0.1:3218\n</pre>\n\n<p class=\"h6\">4.Modify Hosts</p>\n<pre>\n#all port\nnews.baidu.com 127.0.0.1\n\n#only 81 port match\nnews.baidu.com:81 127.0.0.1:82\n\nnews.163.com 127.0.0.1:8080\n</pre>\n</div>"
  },
  {
    "path": "res/version",
    "content": "0.5.2"
  },
  {
    "path": "script/create_dest_zip.sh",
    "content": "#!/bin/bash\n\necho \"bye bye\"\nexit\n\ncd $(dirname $0)\ncd ../\n\nif [ -z \"$1\" ];then\n    gox -arch amd64 -os linux\n    bash build.sh windows\nfi\n\nversion=$(cat res/version)\n\ncd dest\n################################################\n\nif [ -d conf ];then\n  rm -rf conf\nfi\n\nrm -rf data/*\nmkdir conf\ncp ../res/conf/demo.conf conf/pproxy.conf\necho -e \"name:admin psw:psw is_admin:admin\">conf/users\ncp ../conf/req_rewrite_8080.js conf/\necho -e \"news.baidu.com 127.0.0.1\\nnews.163.com 127.0.0.1:81\">conf/hosts_8080\n\nt=$(date +\"%Y%m%d%H\")\n\nrm pproxy_*.tar.gz pproxy_*.zip\n\n################################################\ntarget_linux=\"pproxy_${version}_linux_$t.tar.gz\"\n\n\nmkdir -p linux/data\nmkdir -p linux/file/\n\ncp pproxy ../script/pproxy_control.sh linux/\ncp -r conf linux/conf\n\n\ndir_new=\"pproxy_${version}\"\nif [ -d $dir_new ];then\n  rm -rf $dir_new\nfi\n\nmv linux $dir_new\ntar -czvf $target_linux $dir_new\n\nrm -rf  $dir_new\n\n\n################################################\ntarget_windows=\"pproxy_${version}_windows_$t.zip\"\n\n\nmkdir -p windows/data\nmkdir -p windows/file/\n\ncp pproxy.exe windows\ncp ../script/windows_run.bat windows/start.bat \ncp -r conf windows/conf\n\n\nmv windows $dir_new\nzip -r $target_windows $dir_new\n\nrm -rf  $dir_new conf\n\n\n\n"
  },
  {
    "path": "script/pproxy_control.sh",
    "content": "#!/bin/bash\n\nCUR_DIR=$(dirname $0)\n\nBIN_NAME=\"./pproxy\"\nDEFAULT_CONF=\"./conf/pproxy.conf\"\nINTRO=\"get more info from github.com/hidu/pproxy\"\n\n\nCONF_FILE=$2\n\nif [ -z \"$CONF_FILE\" ];then\n    cd $CUR_DIR\n    CONF_FILE=\"$DEFAULT_CONF\"\nfi\n\nCONF_PATH=$(readlink -f \"$CONF_FILE\")\n\ncd $CUR_DIR\n\nBIN_PATH=$(readlink -f $BIN_NAME)\n\nif [ ! -f \"$CONF_PATH\" ];then\n   echo \"conf file[${CONF_PATH}] not exists!\"\n   exit 2\nfi\n\n\nRUN_CMD=\"$BIN_PATH -conf $CONF_PATH\"\n\nfunction start(){\n    nohup $RUN_CMD>/dev/null 2>&1 &  \n    status=$?\n   if [ \"$status\" == \"0\" ];then\n        echo \"start suc! pid=\"$!\n    else\n       echo \"start failed!\"\n       exit 2\n    fi\n}\n\nfunction stop(){\n    list=$(ps aux|grep \"$RUN_CMD\"|grep -v grep)\n    if [ -z \"${list}\" ];then\n       echo \"no process to kill\"\n    else\n       pid=$( echo \"$list\"|awk '{print $2}')\n       kill $pid\n       if [ \"$?\"==\"0\" ];then\n           echo \"stop suc! pid=${pid}\"\n       else\n          echo \"stop failed! pid=${pid}\"\n          exit 3\n       fi\n    fi\n}\n\nfunction restart(){\n   stop\n   start\n}\n\nfunction useage(){\n   echo \"pproxy useage:\"\n   echo $0 \"start|stop|restart\" [conf_path]\n   echo  -e \"$INTRO\"\n}\n\nif [ $# -lt 1 ]; then\n    useage\n    exit 1\nfi\n\ncase \"$1\" in\n    start)\n        start\n        ;;\n    stop)\n        stop\n        ;;\n    restart)\n        restart\n        ;;\nesac"
  },
  {
    "path": "script/windows_run.bat",
    "content": "echo \"start pproxy,don't close it\"\n@echo off\npproxy -conf=./conf/pproxy.conf"
  },
  {
    "path": "serve/assest.go",
    "content": "// generated by goassest(0.5.3 20161126)\n// https://github.com/hidu/goassest/\n\npackage serve\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"flag\"\n\t\"io\"\n\t\"mime\"\n\t\"net/http\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n)\n\n// AssestFile assest file  struct\ntype AssestFile struct {\n\tName    string\n\tMtime   int64\n\tContent string\n}\n\n// AssestStruct assest files\ntype AssestStruct struct {\n\tFiles map[string]*AssestFile\n}\n\nvar _assestDirect bool\n\nfunc init() {\n\texeName := filepath.Base(os.Getenv(\"_\"))\n\t// only enable with go run\n\tif exeName == \"go\" || (runtime.GOOS == \"windows\" && strings.Contains(os.Args[0], \"go-build\")) {\n\t\tflag.BoolVar(&_assestDirect, \"assest_direct\", false, \"for debug,read assest direct\")\n\t}\n}\n\nvar _assestCwd, _ = os.Getwd()\n\n// GetAssestFile get file by name\nfunc (statics *AssestStruct) GetAssestFile(name string) (*AssestFile, error) {\n\tname = filepath.ToSlash(name)\n\tif name != \"\" && name[0] != '/' {\n\t\tname = \"/\" + name\n\t}\n\tif _assestDirect {\n\t\tf, err := os.Open(filepath.Join(_assestCwd, name))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdefer f.Close()\n\t\tinfo, err := f.Stat()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif info.Mode().IsRegular() {\n\t\t\tcontent, err := io.ReadAll(f)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn &AssestFile{\n\t\t\t\tContent: string(content),\n\t\t\t\tName:    name,\n\t\t\t\tMtime:   info.ModTime().Unix(),\n\t\t\t}, nil\n\t\t}\n\t\treturn nil, errors.New(\"not file\")\n\t}\n\tif sf, has := statics.Files[name]; has {\n\t\treturn sf, nil\n\t}\n\treturn nil, errors.New(\"not exists\")\n}\n\n// GetContent get content by name\nfunc (statics AssestStruct) GetContent(name string) string {\n\ts, err := statics.GetAssestFile(name)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn s.Content\n}\n\n// GetFileNames get all file names\nfunc (statics AssestStruct) GetFileNames(dir string) []string {\n\tif dir == \"\" {\n\t\tdir = \"/\"\n\t}\n\tnames := make([]string, len(statics.Files))\n\tdirRaw := dir\n\tdir = path.Clean(dir)\n\n\tif dir != \"/\" && strings.HasSuffix(dirRaw, \"/\") {\n\t\tdir += string(filepath.Separator)\n\t}\n\n\tdir = filepath.ToSlash(dir)\n\n\tfor name := range statics.Files {\n\t\tif strings.HasPrefix(name, dir) {\n\t\t\tnames = append(names, name)\n\t\t}\n\t}\n\treturn names\n}\n\n// FileHandlerFunc handler http files\nfunc (statics *AssestStruct) FileHandlerFunc(name string) http.HandlerFunc {\n\tif strings.Contains(name, \"private\") {\n\t\treturn http.NotFound\n\t}\n\tname = filepath.ToSlash(name)\n\tstatic, err := statics.GetAssestFile(name)\n\treturn func(w http.ResponseWriter, r *http.Request) {\n\t\tif err != nil {\n\t\t\thttp.NotFound(w, r)\n\t\t\treturn\n\t\t}\n\t\tmodtime := time.Unix(static.Mtime, 0)\n\t\tmodifiedSince := r.Header.Get(\"If-Modified-Since\")\n\t\tif modifiedSince != \"\" {\n\t\t\tt, err := time.Parse(http.TimeFormat, modifiedSince)\n\t\t\tif err == nil && modtime.Before(t.Add(1*time.Second)) {\n\t\t\t\tw.Header().Del(\"Content-Type\")\n\t\t\t\tw.Header().Del(\"Content-Length\")\n\t\t\t\tw.Header().Set(\"Last-Modified\", modtime.UTC().Format(http.TimeFormat))\n\t\t\t\tw.WriteHeader(http.StatusNotModified)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tmimeType := mime.TypeByExtension(filepath.Ext(static.Name))\n\t\tif mimeType != \"\" {\n\t\t\tw.Header().Set(\"Content-Type\", mimeType)\n\t\t}\n\t\tw.Header().Set(\"Last-Modified\", modtime.UTC().Format(http.TimeFormat))\n\t\tw.Write([]byte(static.Content))\n\t}\n}\n\n// HTTPHandler handler http request\n// eg:on file system is :/res/js/a.js and request is /res/js/a.js\n// http.Handle(\"/res/\",res.Assest.HttpHandler(\"/\"))\n\n// eg:on file system is :/res/js/a.js and request is /js/a.js\n// http.Handle(\"/js/\",res.Assest.HttpHandler(\"/res/\"))\nfunc (statics *AssestStruct) HTTPHandler(baseDir string) http.Handler {\n\treturn &_assestFileServer{sf: statics, pdir: baseDir}\n}\n\ntype _assestFileServer struct {\n\tsf   *AssestStruct\n\tpdir string\n}\n\n// ServeHTTP ServeHTTP\nfunc (f *_assestFileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\trname := filepath.ToSlash(filepath.Join(f.pdir, r.URL.Path))\n\tf.sf.FileHandlerFunc(rname).ServeHTTP(w, r)\n}\n\nfunc _assestGzipBase64decode(data string) string {\n\tb, _ := base64.StdEncoding.DecodeString(data)\n\tgr, _ := gzip.NewReader(bytes.NewBuffer(b))\n\tbs, _ := io.ReadAll(gr)\n\treturn string(bs)\n}\n\nfunc _assestBase64Decode(data string) string {\n\tb, _ := base64.StdEncoding.DecodeString(data)\n\treturn string(b)\n}\n\n// Assest export assests\nvar Assest = &AssestStruct{\n\tFiles: map[string]*AssestFile{\n\t\t_assestBase64Decode(\"L3Jlcy9jb25mL2RlbW8uY29uZg==\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9jb25mL2RlbW8uY29uZg==\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/6RT3W7iRhS+n6c4km8rflJVinxVVXmAlbbqLfLC7GLJ8bj2UIqqSLCCLLRm7e6G/ABRS0lU2irAVUL4y8t4ZswVr1ANQ1rSXFRq58Yz53znO9/5Zqz954U0eLYcxyXfliCHDwlkif36OUIuDf2PrkjjQRgtO9GsL8Jj3m2y73uiXRV/jFjQRw5xKeiwn9pPIaSJYU+Ex6Llry5/+QuznvvRZJqKewNxNWUf/F2iaPEgTgaiM2Gh/zepkTs07ReKOYUQNamFQYc8tiyyHRnZhJpZGd1u1EeqbY15c8huzvnJUnSGbNFaz33ZYXQfTd+zxUfWaK5qTbEYinY1vhuxZRXlDGocmC7okEgk5SGJkLa6vODlCj99F81ud+nQa9PCB6arg0TLQxL9oy+7+o23xuu5n4omUz6eRPc1dnPO3g7W87okaTRZ8DvrDlbvmiwciXaVn92y8kU0b8cPnbjnKy4+qYnweD1vbPS9pMTFB0YJdEh/hpC2a2M8vIpHFX56z+YB0ohDTWJ7+nc2saVD/OxnBfjkleGZWT1PqQObLahIhrolnY0v41FL5r6QMVXxCDDskh7NZrwasEnIgrsjZBRo/suSo27Alsav3vajacfFXxewR9kH38WeQ2wPq2HUYMqFHYlgWJaU2CjzbgMAiG2VMq9cYuSyhifvnwU/rsoVVh972PNMYoNlelQ61mgqsiP02Oil8Y2U85QCIW1byepncW/Af7oW3R+UJqTBVggoJbrSEU2nLBjFv1bAdDLEzRQ8LN9GvPzIatf8pi968u2YDq+fxuWazLLwvao4QttuX5m4CLokRUjDb0AaqyeT6VQinUrsJfb0T9N7+0Dcx4RtHGLd8YqfP0Ug7V8AQPMYNgINOweOV4SiaVngGJ4HNO+Swps8ULJBOYaLbQrq/1GHF3Kv/wkAAP//AQAA//8Vmt1TlAQAAA==\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9jc3MvZmxhdC5jc3M=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9jc3MvZmxhdC5jc3M=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"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\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9jc3Mvc3R5bGUuY3Nz\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9jc3Mvc3R5bGUuY3Nz\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/6RW3Y7bNhN9FX0xAiTASpDWdr6NhAC96hO0V0UhUOTIIpYmBWq0tkvo3YuhqD/baS+KIIaWnBkOz5w5w194w2wHGH36/bdf47dPRcIVMOv8b14ZbIYGz+qlMuLmzsyepM7TomVCSH3K02Gn2YerpUKwOVNtw76YlnGJtx/f069F+M6T70XF+PvJml6LfFfX9RKimKOuTQ6Hb7zaF9woY73DsDuD7t1FCmzyt/Tz7BaxHo3PI+qV26yuDlGyw7jDm4IYby3k2miYnCIlXa0Mw1xBjbNTlrbXojYa407+BXl2aK9FZawAG1t5ajDP2mvUGSVFZE8V+5K+0L8k+1pU5hp3DRPm4m3SKB0tXo/Hl+l/kmVfx+gX8NH+n6YFwhVjpuRJ5xw0gh2S8cSylrZDF46nNP/76dP1dxSu7PqKAI6UzBvzAdbdFeyfrSPmQqnGwq2gjZgTsmsVu+VSK6khrpTh78VYySOBvK6yBrwY+x5jFaFwH2BRcqYCKGjaYcc6KSAQYb//XJyljse/DhRtSC7Zaxr2s9ewcphXDmHlOK94rx03WgPHskOGfecmFnzb5oesUjDVgRulWNtBPn1M/OiI974/EqzKLNivSrbjnBc+VqzYzfSY1/IKorgYK+LKAnvP/W/MlApIZWn6+aGLRrrHlUE05/xIN6MDI85alEa7B0JtI6T1of72wMJw9RhNSyGLZtx6Pc4NcH+TcO2QRrh1xJZu3M+ZoY2weVm+xYz0/qfhPWumLNIlVANMjAHdv3bS5uKwBwYwhSFtC2FWbr7Hn8E1wTOKwII51sbg1Aac8yFBUXK64ZO2RlHauy0fb0iw5I8O/5Pn1lhk2hvYB7ftvlrvU7+ut1umQREn13gc4RWqWfkO1A+hEctR3Mva2HNUS1CiA3RbDKi6O6zK4OJWopm114mkRKf4bWtKEJB+1Mpcci/ZvLedsXlrpAdq508oudEIGt0qFAG/3Y18QxG9nq+L+8SeqcvWs7VTs9OsE/KjXHIvaabcZX9m14moGRChSZzCwqhOaJMOFHAEsSkBr2FI/OFhFgU6UPlW02lI+Ho2Jw1p4aSvYait0iuF/JgI/shuT8NeuWU4+hCR1CSxT0Z0cKCB+dxnQEEmDetoRMytna4IuLGIRn1cngAz1pVI74b5PPqHhMgYU42sUW4SBlLq5WEyU3Ua2UzIvhuH+oPKnCy7UWUsEI6hhyvVU0mgK1GU4f2zVJd0qJiL33FrlBoSYkhVyqcTb0iUIfJ23AJot2ZGSsHCRPPf25s/6seuEj9DZyPfe6+WBFeZjm3glmmybDwRvmD2lj7vk8lV6rbHP+hJ9YNC/LkKfzecXteZiESxDoPx93SpXHjb+LSNBkLPrZR/QbyRQoAe5PnktufEpEZ/AwAA//8BAAD//+I2kz/XCgAA\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9pbWcvZmF2aWNvbi5pY28=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9pbWcvZmF2aWNvbi5pY28=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"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\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9pbWcvZm9sZGVyLnBuZw==\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9pbWcvZm9sZGVyLnBuZw==\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/wCMAnP9iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB9sFCBErNh1XQGQAAAIMSURBVDjLjZLPS1VREMc/M/d4n7osqKBFuSwjoR+uMhemIUEQuGnXvl2tgsD/JqKINklRVBAiRgZCFrUoiIxELXq+fOa998y0uPe9rlDUbA5nmPn+YuAvNTV9j/8pmZqeeR5Fh3EQABdCmry+dX38yL+Wp6ZnkMkrN3zi7CQec1SFJAk8ePLM0zQVJEEBA1QBB5EOSePNzWunB8OP5jpb7Q0W36+jKAN7+xgdHhJDcMDccFdijJgLZgbaw8LLF4cBwsa3FZqtTYqtTRKFdx9bxDyytrbMZvM71rEmpYLoMLB/N4tzj8sMDo5c8kPHR/nwaY1EBRB+brU4N3aMC+fHMPN6ZIDRCAmWpLxdevUonDg1ytXLF2m1t1EVANyF7e2MxaUVstyQapVSBCEIEnp5euf2ePCkn9mFLxRZ1h0AUBE8gR4tQ/QKRIBoTkMU0UBwF1SAij0BYgfIIANC1ZOamcIcHIJ7+YnmCFAAShmWSLmUVYDaAXYwcwp3grtj0Smi7/Dp3ch+l9csFtFwc4KIoJqQqHUtdNiseqUGVvYdTRIUIax8bXJ/fgm3YgeT1lT4H844pH0sf14lHNi3i6Gjg8Qi7zLVpdZ7VgNOG33Mrc4TNtrZwyy3iSJ3RMC8DLKH6u4rSXkFFARwJxJp535X2HPyDEU+AgjuiiC4S9e+O4hUAqQUJ2I4Tm//7C/8V/xJTO95pgAAAABJRU5ErkJgggAAAP//AQAA///J9dz9jAIAAA==\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9pbWcvbGlzdC1hZGQucG5n\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9pbWcvbGlzdC1hZGQucG5n\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/wA0Asv9iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAABuwAAAbsBOuzj4gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGxSURBVHjapZNNaxNRFIaf+zVJ2klMad24SBBdmLWCFUQRROg/cOci+gPEjRtbdNOVYEH/QBFc6UKQUhduxC7qBwiCVLQBFURxTDM2k3Tm3jtCRXDhREKf7ct5OLycI/I8Zy9ICri2fvnumYetwdlHR6Lld0t3KKBwg/Orc37u4DmRuiGvoxf29sn7ZqwNXn59LrwZUqpo3m690RRQGGTe8XMnQUhJ6hz/EwhAAfZPYJ0nTgcIBJl1/5pzQK4B2ivtxU7cufLsy1MdKE2gFUZJkmyIFIIdlzH7oJlXjKESGI7uP2EbtebNS4cXru6WaBbN94vHLkyjHLnyCCl+C3y8K6jrOlJqSoRE/R5x8oNscjO6d/rVjAaw1rIZddCBxpQVtVKIkYK+20ZJMLkhSRM2og/0BgOmgiozQfpXB575x++f3EJj0GC0JFCK2WaLySBg7eM6ZaMpaU011JggzqzV8yPvoLxk8lOHWkxNlFnrbPCp3RNj3YHznsxlSAGZ9xShRwm+bffIhce6sQXXZSOs55+7XdHtZ4R2nx3zmRb88enqMjA8MNHYqvnajZHPtBd+AV8ir6y+hjXrAAAAAElFTkSuQmCCAAAA//8BAAD//3j7Bz40AgAA\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9pbWcvbGlzdC5wbmc=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9pbWcvbGlzdC5wbmc=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/+oM8HPn5ZLiYmBg4PX0cAliYGAQAGEOZgYGBg1d/mAGBgbmYifPEA4OjtsP/R8wMDBwFnhEFjMw8F4HYUYnjdkVDAwMkiWuESXB+Wkl5YlFqQzl5eV6mXnZxcmJBal6+UXps9/ZSDEwMHgE+IS4/v//nyENhKLmQMmoOf/9/f3Ly8sZ0v4rVYG4ENLf3z85Oblw1f/y8vIHDx48evTo5cuXHz58+Pbt258/f3g6ps5lYGDgKwnyC2ZISUtLT89saNixY8ezZ9bPUv4yMDC4ero4hkhcnnpuu+ABBQaWg+wtgoeUL9cvV1L60ZLIvcOyYeaKB6+eCHS5/2v7vrM6W/K4ZsLllI3LLF9Zan1b/OpSjdSPkDy3+sDj7EvvzPm8hoGBgcHT1c9lnVNCEwAAAP//AQAA//8A3/5bNQEAAA==\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9pbWcvbG9nby5wbmc=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9pbWcvbG9nby5wbmc=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"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\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9pbWcvdGV4dC5wbmc=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9pbWcvdGV4dC5wbmc=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/wCrAlT9iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAbrwAAG68BXhqRHAAAAAd0SU1FB9sBBwINDzIP4PcAAAIrSURBVDjLlZPNSltRFIW/k3uTKAkxQXQo1KgDpaWTDCuOKxVRH8JH6LCDCsVCCzGd+w59gA4zKXZQqBQMWLAIyU1sfszPzT1ndaAR06al3cNzzlpn7bX2NgCzs7Pper3+EPD5t4qSyeSXwWDQHB080X8W8JR7P3oArw8P2d/fp1at0u50sNYi54j7Pr3BAN/zmMlmmZubu8OYW4INSR8G/T69bhfP8zDm5srEYtgoIp5I4JwDIJVOY4zZAt6P9fyuVGJre5tOu00YhkxPT9Pv9/F8H2stM5kMrVaL/PLyHWZMgY0iwjAEwPdvuI0xYAxyDklgDIlEYrKCUqnE5uYmnetrrLUk4nEc4KzF8zxyuRzNZpN8Pv9bLBsjd8MwVBRFkiTnnKy1CsNQw+FQvV5P3W53lMIzfs29WCyyt7dHEARIIpVKEfd9nEQQBKTTaVrNJg8WFyd7wK1cE4sBIOeoNxqUy2XkHNY5pqamVCgUzPz8fAH4ONZCsVjU94sLfTs/V6VS0cnJiQ4ODu7Pj+u023r86NHztbW12EQPnLWy1mo4HKrT6ej4+FiS1Gg03NfTU62urr5YWFjwRsAxD46Ojtjd3aVarZJKpXDOcXl5CaAfjYbZ3tl5FdRqL2tBYP+ewq3jQRCoXC67bq+n5ZWVN7lcLvGn7VqXpEqlIkmKokj9fl9XV1c6OzvT0tLS20wmk5wE9AGy2ewnY8w6EJvwpp3NZj+3Wq3hJIKf+1KUYNzdR+cAAAAASUVORK5CYIIAAAD//wEAAP//kff/kKsCAAA=\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9pbWcvdmlldy5wbmc=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9pbWcvdmlldy5wbmc=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/wA4Asf9iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB9sDCwAbGenR2McAAAG4SURBVDjLjVM9b9NQFD33+RkTBkPt2ApyMpE0UVQ2xgyN+A90ZmAGJJb+hwqJja0j4icwwMRvABUydEhd4diJMKEhcfwuAy74I5Y40l3ux9E9576nDe6PKQzOmwDaAJo1YQOg/nC8imbnyIMAONPpxUvPcyxAKeyEEBfTYNHutJ8BCPMVCcDyPMfqncrRJCITXJoloGtz/PWx+zHbpEJAgFKTiEx+EbzFWugFAkMldOIeAbwFcA8AA5j3hw+js0/vWf5tZABroc+vtAKBdV1TVxu18I/pTjPOyxG7FFMWRRs2W/H67qh3qo28truXyYHA/yLVJT/5/G4SCTMzm649qIBrkj9/SVleTRb2NlRilQcNlVT1VAiE6Noc04l7BM4ZwP/OiGS3XAmAVUral0eLDyR3PyTekvi+0TSdAJQ6BIC5fxnMUsNsbOVe48f6hlY2gXRWt3nJt2x9WfFgcHAYdjre8+zkvWXoHztvWg/CmIxCM/2R1LU5BoTIp/Pop2nySqziFWrlCME3zYYm9acAzspnnPt+MGu1XKfWdg249L+FAKJKbXBwSNn33QfQr4l9AM3+cEwA8BsG1aBqp74kfgAAAABJRU5ErkJgggAAAP//AQAA//92SZjSOAIAAA==\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9qcy9iYXNlNjQuanM=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9qcy9iYXNlNjQuanM=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/5xUWXPaMBB+z69IeWCkMQEsOQ5ElmdIeh9J2/RMaTNUyOCGCGrkXIb/3llJHMmEkPTFmtXufrve79Oed7LNvc5YhgEvTk7l1ZHOdkutvf2nz56/ePnq9Zu37w4O33/4ePTp85ev374fd36Lrkx6/fTP6eBMDUd/s7HOzy8ur67rPqHBdrjTaHo1XqpIJYZduZvkSuh0qFCqRrnGBZQb5nqUa14qMbBEP/Mrop8R+FDI8+FD4GPMwISlvM4MBrfdVk9ynTRObBmHzi766UCiNDJmdSBVT/dxARW4vRL9TrY/7MqWRqnnYQZ1V7voChf0yAE1jgkYhCMEZpniKArwBAwSx4GJpNZJyv42jiJivTSOQ+MNAIeWQ8rSBKXjg86BCca4MKkmIgzYVA7GcnM5hNoQ691wI7WHt6H76bjq2DTdtzSCprG3wkPwyiS6MinAbLqRSZ1nynHKppWu/C/ezdV67i0fmRwNOkKi2o9fra3jztZ1favZ9tq1Nv9Z61VKpVVCMLzd+JlUdeXlYYIWPDuOseX1EcH0McHBg4ONeA15VjzQlpGWkS4ytpVWYL00jolTr/FSo8oQT8w4bwrlSGep6lWTbHi27zRuhIxBjZD7hIcBLh6UREANNi14RBrFbDrX742nbZWErAuz20Jbfv8LuY1NFVzYk9tjIZh21lYgkbYqYSOtXCdaXhpRJsMMwZXidaYil2mlw5TnWQ2LGeTSTlBmXCLySQMXDtDjd/4vzGj2lJGIfbKDy2UkIlIPGnhNMhKwNCZ+k2C2JrAcUjyBdly59cA+wRNCgnXItocF/MP7mG8KlzJn8PbCcH47bkejWxmwBywJsH8Jr8/fuUtarHw+u1ne3cs8WeSVNKWed4uqpu+oIgHGhSB3VvB8zO5DhplQ375HJAjMB2pxMiPqHlxB73aR9SXNfgCKkSvqGqDzBugSQxaNTaf/AAAA//8BAAD//7lfkqMcCAAA\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9qcy9kZWZhdWx0Lmpz\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9qcy9kZWZhdWx0Lmpz\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/1TMQQuCMBiH8a8SEmzD2D3EU/UFqmMgs/1nQ3k35msp4nePAoNuD7/D4wa6sw+0iTGFcarY1FU/RMkmNWA1b9fSzpOVGWNkk2AypesPiBaTDS8Su/UkoWbvJHSL6RAsynKvZuiY8ATxEc4MHUtV8MP3ugefDTW4YmQpbix+3uF7O5Et8/zfLmwSF8uiiuUNAAD//wEAAP//UCCwb78AAAA=\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9qcy9qcXVlcnkuanM=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9qcy9qcXVlcnkuanM=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"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\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9qcy9zZXNzaW9uLmpz\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9qcy9zZXNzaW9uLmpz\"),\n\t\t\tMtime:   1478614292,\n\t\t\tContent: _assestGzipBase64decode(\"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\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9qcy9zb2NrZXQuaW8uanM=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9qcy9zb2NrZXQuaW8uanM=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"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\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9wcml2YXRlL2NsaWVudF9jZXJ0LnBlbQ==\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9wcml2YXRlL2NsaWVudF9jZXJ0LnBlbQ==\"),\n\t\t\tMtime:   1448806450,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/3TUyc6jOBcG4D1X8e/RL4ZMZFELGwwGAokZA7sEwhggEMCEq299X0nVXeouL189R7L0Hp3/fz2INN3+n4wcT1d1GXjoO2UsXVfaVZZB98gB1SHIdQOYcAL+wHqHbrIAr8lur7n6faMQBCHxgaVFi7wCA+Z2wEAQeeBZRJbjU0QjJSAEK2BBcRgXabjwOrJfKa4XvIL0awCCzlKb9JVqhRCVu4q5i/x805516h5pgo358Ru2fsP/YSmDi8S2PJ/aHlgtz18sxdqEX1nlU1ux6K+sgo1F3lQm37/UEDWiUEEBY0FLA4KPIKWWowVNdA3eqQyV29XZWY5E8c8BU4Fxe7s6XRrqUyQex5NYvGLsz0yC4ee+Kf6JlT/hX1bXoV4BG+Z1zxR1qR0pDwFBKgBnGRAJfAE5N2VAEOCN9/UNS+6d5bLTZw/3kWXC7dk4ZZrxNG6ZauTEYjSban1OBpfxbDmYIg/O+vYmj6ecXc3uZUi3R037RyfOjVQf8SgtYXLd5wd9HzGxjZSgGtTLM4lTFqtZLOojPvARMIjeWrhH4TDYsu1wbYrbJ8lZ7A+A7dINrspHTpiJOzdBcLm5WvkZgZocydrLU3QZzXM8y+3ehJfrprneB9iGGQ/c13poU+fiZNGFt3x+YkYWZHZSbbmnMrvK2VSDu+8+9pdh2SbzFtcJmS5tvvb4vH089wBmfBwaFaRzrIahsL0yyBCMRTwrRhOxoN9wn/4YH62qnQL4PpCqw3rvW9MaPuSD5cLYl3fLziW6AgiAnQAo41U/tw6TLVJz4l+xfe7m5cTaILjm0ymYMZvs/Rcb+RR/rbrDVxDmVO3At2X+hBXwjT0IfAoogtz6s/e/a/e/a2e+um4E81xNjmk4lZ+7SR1lgvzShsE12cj5JO/XJfNyCcUC7yHn2FVaJS3qjkRhvuMZJcrVftndw1PzGfU1Y893AZR7KhxL9jRPZieyM6hgI5EsGPqBo+mq6AWUK3YuI668M4ez5qEKXKxa2B6TD9dMrDTe9ptUG67C7q7DU+ZuxXZsvWdmB6Xop6M78vhew2KdpGfHUG2DPRre1dNH8jDXFN50U9FR7k9r5AP29KlFzlDMtsDOq1YueVXGdpmSTLlIvG7ZHCODZ8JlQg0DQcVn3yX5eitdsys3n9c7YLP2ZCN7ZZMKIpTr5QZy6c3B7Bj0ZC44yWFOc+Sp6vYOkrSbopL/iM/HNcPFi/74wXxfPWQr/76EfwEAAP//AQAA//8Ir+SsJgUAAA==\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9wcml2YXRlL3NlcnZlcl9rZXkucGVt\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9wcml2YXRlL3NlcnZlcl9rZXkucGVt\"),\n\t\t\tMtime:   1448806450,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/2zVpxKkUAKFYc9TjKe2yEmMgAs0OTRNdDSZJmd4+q0dvcce87vvP/+bIL1U68/b4/84bzXgP9IfXYr/PZCpqtLEqwLP64B3JR7V1mgVGmQtK/Cey8IryhJLu/7d5CV6JkO7IXi96X37dLuGlCgEN4uOo7ytkinYjAp+9HHS2LT4nXMx4kfP/jhlY68wi+iKUek4sSQxaBfZ6bIkhxUZKhNc3RQGjXnNVQdTmaVwWSxgvZEhV4bOrWDFX3h4zAmlbYrK3RG7DwIn9V7NvfFyBnHuM4M9djbdTg4w0LrgREQffRdhCEuU96aHGfK38y5jBzV9dN9gvrSylkQ68fBEW4fk4Ot7Be0sF5kdpPLL3N0ZqmdWbLLoaF4o0STUWuE8EjkMMTKSNEy7cFvU+hjmZwKB7plLOLMd9kBYGbcdFXX2zf0JC8CYnpD4gLooz1VF3uUFflQF3gWsNFTgKbDQNuQfNPyqFUnoOw9xjqqjakhhn5/2m6ouftYamXv1S1H7uLq6WY2ZP4sT8P69Wcedmi0GREgv2KE/6fK2LnteB8fR67VV7nYmn8BIIn2I37Bbcz5A+plJl+0C9mbJZiIH4SIYNwr9Vq7Jac2XW6VYJvn3ra3YNVFkM5Ca3aTRJn/p4H+vmdoHVsZAh1vXOwaVGh72i7JsyE8CZ2vp8Vb8m7Q1gqisn6RhpBKLOIrKaHOyS93sFZPoaZSznneRt3TYPvBcmJ4CGpI123UNna0GPGBj3XAt/5tvE6mNrlekqlGS+h66JE74aoiEkaqOTYfjeA2sQbTeqQqFIeU0BU7x40vgneJgSzqMifWaImWyzCXSWwagn6CENfcreR7RmpPVw1gj4Tt/cVwB0VNkfkMFYQ42bHOjUM2XbE2rilvg+bpwVpWLgnqC1ThP0U3TKxGXZn7tN148LhFPOzSZ5kLpN3BgAYwm5eiJ+8HncG5ubBOo3nFMfyUpVfu+OOpFUIdPmD0oHOZfsVV8oeh8yWoPRPkBFNGi7CuBCbO2WmOFaUVkKJvPDbv3Tk2BrUZMO8rDr0eMTjj1zjg+KEgo2LSjggneu0TDTWLu2+6JJnJg1Wscy60pRAWMt6Aa89KPniKjaQDub7cWWX65XgdJBhtU4kfOhupMNi29koyJ5gJ/9U/ah1hNEOinr4HBjy8+IMN9wnCXSTonO1hDnMYA+kYOR33e91e0sk9k9tNG1Hukrt2kcmK/yU/s53qmsDa3vZJ2aReRykKMx5F3rbFELUFRxlGolAQD4x/YUMnW/sqe4kXoCDbrGK21VRT2bYq+KU+cGwtwSCKJqwYu7uIkl/egGNWUL+KfVbk9VXqM8NkR8AcFVcwvSLGTE40rMJM/w/cXPlHNwk1V1yrL9qjI6/qrhmBsBxdHzL0xwh/JbHZGWFTvtO+Oyhg3/THrGcmKR52C2X3wKcHsQVIIkGQHe292S0ESsGkCJ3Vdk++fS3iHQ2F1IDw+ay/hoTN3v+mhx+7ipq58Ig953e/aRHQr7+G6Sa4QfDFj6OpC5QJfzdZl4RxKBytrfJpD8ZLviX8vweN1RDaG9xdJiEZCZRRUzFqO80fIoP74oCEGBlROo34jVOcH11X+09+xhwxjpucKlvO63ajkOuY0J6Lxukzs+b6te3Tf5wJhdoSZARbkPiWuAD5VicF9cqKzjfdTPjVJR6GsTpmNRbwVITh0nCLF6u9f6B8rkiX+f27+CwAA//8BAAD//xldrVWPBgAA\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy9zanMvcmVxX3Jld3JpdGUuanM=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy9zanMvcmVxX3Jld3JpdGUuanM=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/4SSX6ubTBDG7/MpfPdKiZj3rhBZSulNKRRDcwotIrLGMW6y2fWMq2kw+93Lxj/Hes6hdzvz/MaZecaikQfNlXSqCtXvW4pwRa7BRXj2OoTn4AiaDlrFkF3q9KCqm9UDhfzIpSXu9854oc1Vqv4Xb5G+oFDotgyds8OlMyNKYDngo398TugrJT4na0JCs7LFhcJLOptSZae0BFEBusP8Xjhx8/EWoJV6sqkhLbgAOprj2mjHdOl144uOjzUhK1veoJhyQd1ktUb3f/+DRykpta62mw35OOpbd8ztdt+jn7/SL9H+iazJptiQ9dTLrD7/2D9F39Kv+xWCbvDhUWhWy5vNfVbZyevsEhKuUXaiEq5OlJ3goN2F3xPJEB/YJ0R2m1F8oOJz4nUMMeYJ7cOYD/73TeyNGGJoxjH79OtBZ463TDRQ2xPbiu4Ieju5LdkFRsXpwdjmEuPXS85vmbBrvEA0bplIjM/y/B2UtkzYs/HC1bcKVPFXE0pJI3MouIScvPXpYUvzTv1/lPSGv1U8RWtCEvv/vmSCqqlL64tn/BzE0o4cBGhY2CFALjlePB6UTkssrAwEyKMuDYgaBsWdf/V+jxNvhIwxfwAAAP//AQAA//9Fj23NIgQAAA==\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvYWJvdXQuaHRtbA==\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvYWJvdXQuaHRtbA==\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/3yQsc7aMBSFdz/FldUBJBSn6gaOB7p0RAJ1RY5jEoPxtexrKEK8e5U00O1ffb7jq+/Izt3AdQ1vu5orBrJNQjEZwXidc8OHH1zpFgtJEcc4ql+Hww5iQkKDHnTQ/pFdBkL01Qfa6mw7wADbPehkBkfWUEl2dU+OyAZoH9Cj16H/39klPFtDsAapYUj21PCBKOa1EL2jobSVwasYXFdEjAn/PDiQTr2lhh9br8OFq695KbT6XPtZUrKB4LdN2WFYgzxhIDDoMTWtL1Y9n9XtX/h6STGmUxvG+jRZsPfjTByzR+Lv36cNmRSduyk2Lzq/ZZNcJMWypYO7Wiy0OJVgyGFYLJ8M4FvVW9pP1OLjP0pUs5TDWUeYwZpLdc58uWGv1fe6rpcbJsX7xF8AAAD//wEAAP//Hz2bTdsBAAA=\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvY29uZmlnL3JlcV9kZW1vLmh0bWw=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvY29uZmlnL3JlcV9kZW1vLmh0bWw=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/5RTwW7bOBC98ysG3AViA4EY2UA24FLa06KXHnsrCoMWRxJTiqOQVBzX0L8XlJ3GSFGglQBR4nvz5j2SUsY+Q0xHhxVvyFGQXdBHXjNPCSVT5GqmnK3HKYFqySdYWNXeTVgLYTtPAZXISA06QeoRWhtiAmc9QiI4UxbgMSrh7FlwihhuIjxGsBEMtnpy6ZbCwusc7bU7c9npZFvwlKCw8SN11s/zIqA09AHbiguXZ3m9DEroOndFYxMcaQrQTDHRAGOg1jo8i55O6M08M6bEElAY+1wzta8DPoHBgaQS+7cOj/pZxybYMcl/OZBvnG2+Vvzv1c1fY8BdwKddLrpZF4m6zuFqzevY00H01mB2xNQYEKyp+DWfvy68sXF0+ig9eeQ1m4IDCX1KoxTicDgU+KKH0WHR0CC020+DcDam/xprqnJzz2LT46AvJaynmEDCuzo2UsjTD3ds1KkHCVdKrMMk4dRYIz+Xm+2XmY0U88zM8jZ5PSBIYKOO8UDB5PcBU09Gwof/P7Hqzy4mRE4PDRmUKj9rZttVwKcie68qnr3vtTVTds7XJwYAP+AFLe+3C3aN7LQxoeLl5p/iLt/yoeQgBET0JpPysXgFS/lQ5tqWwrDrMBXamBXX/JZrvs6AEAuU16GImFbcXLBZibPlS4oN/DJCr6ncbN9lmIKr+GVvv/XW6Lekgv+kvv199SniLp/wFbfe4EvRp4GvlyRTPP9+MelkG8gksB6MDcDzx1VbJcaQhz6IWu2DqL8DAAD//wEAAP//KQqcVCAEAAA=\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvY29uZmlnL3JlcV9mb3JtLmh0bWw=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvY29uZmlnL3JlcV9mb3JtLmh0bWw=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/3ySwYrbMBCG73qKQaTQwm58aqFZWedS+g5BiUf2uLLkSOPsBqN3L3Ls7NLDXgwa//N/vzSj0mg8nJ1JqZbdD6kjXiDiayRGVZWfWsxzNL5F2NHTrk+Het+nlLNQNsQBYEDuQlPLMSSWYM5MwdeyOgdvqZVgJg7nMIwOGWsZrJXAJrbItSQbj8VDaqEsoWsSshbKYYu+0fO869OeiR3mrKq1KuzkF8QW8mvEy7dZKMY3NhENJL45rOUrNdwdfn7/8tIhtR0f7n59+rUccx7fJHgzYC37JFfa6vk7FeLmqEVEnmIhXl7UKVZaZKHIjxMD30asZUdNg36zKzUJV+Om1fszcfk+xPcQpZRzaWvoul2nhHk2jlp/OKNnjFILMc9kYben9Ce05PN/qdJ0GojlNtwTezixfx4jDSbeHtBkrijLkNElzFnAgl2bFix5G6R2hQE2RLgbq6qh69Lnm4K+H4UK7sPG9E+7KeHRksNDXS63nRaQIy0AAJSBLqJdHmAT7Kfocn5fluPJGf93GdRDcn8pVRktQFXF7T1NiSFU9WGvqrJrD8k/AAAA//8BAAD//+1fByb5AgAA\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvY29uZmlnLmh0bWw=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvY29uZmlnLmh0bWw=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/5yRQW7CMBBF9z6FZYTULopDl+D4FN1HTsZJBsWOOx4oEeLuVQJV6a7t2v/Ns/43uSFMLDM1pdLksz5kDb51x4E3h6ys0beEFSbzNHgrVs0YW+zeXD142Y4ULskBYOx22yKd98FRh/GFsOt5J1+LdL4Ko++sqUlbYQBPEqFUNRTKCsPLqQ8E7ku1LYq1Wl4fPEuKrGGwl3WYKozNcAQv7xlN/r2av7LpOQxKSrm+Gs1gjWb6BQo+jP9A+zFzfvT+FX3w/kT1UokVwmBLLngZXfClwpYWnZJLn6UCzGlw0y6O0e/nsW5xK6UwGvA0X/jaLyUaz1PFrq7yMT2p1dz+s/ge+BMAAP//AQAA///wACsmDAIAAA==\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvZXJyb3IuaHRtbA==\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvZXJyb3IuaHRtbA==\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/yzLwQ6CMAwA0Pu+YukdMR7n2M0PmbSSJkshbYMo4d8Niff3MvIaGQd4IkTzT6MBnDbvauNJ0kjipPfXLN4ZfyndrssGJTxUZ00h21Iljq2a/du7qrBMUPb9Qic6jtyfqoTcI6/lBwAA//8BAAD//7dAZHVxAAAA\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvZmlsZS5odG1s\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvZmlsZS5odG1s\"),\n\t\t\tMtime:   1478614292,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/2xTwY7bIBC9+ysQivbUenYPvbRAL71UqnrZD4iwGdsoDraATbal/HsFxk6T+jTJzHjmvXkPpvSFaMVpo6iomJfNiKQdpXOc+ub4kpKtnL2ejKhycymO2HkqqifTuPlLBR2EULdv1qLx37SNkZQKk2Sw2HEKnR7x6zRzg9cnpS1/+IAKps89cbblFCw60OceRu38R6lUPZueCgZSVAyUvqRwg+UHlEpUhHkrKkKYH8hVKz9w+ul5fqfCTAz8UEophKA7Umv3+tbk3aniZmnuyT1AN/KM96D/oGvljDFCXQMVdQ0JIYM0almDRuXpP+UZ05IbjBXhy3OG+Kp/Y6kySDTSn8yK+WZSv0QVgpWmR3I4fTgkPJ95nYKLsdp4q026Y0tFCIdTjAy8KtUUCNlohZAH1T+0OaX752o+zZL/7hYld3TpplGhXVQJAUeHMe60eXz3W1M5RVqxzE9HKamsbPpRXLOPJKfJHYcdV92Gb/pQsUdix1zL3oXP7ja4B0+Jl7ZHz+mxGaU57Zr4ovH6/45yjn/lWWcnM6zCLW5Y+xkUNzDIT3V9Dn8BAAD//wEAAP//rhRf0ccDAAA=\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvZmlsZV9lZGl0Lmh0bWw=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvZmlsZV9lZGl0Lmh0bWw=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/3xTTY8bKRC98ytQrXY1I+009szOatdDs4eVcooSKdc4suim7MahgUC1PzTxf4+w2844SuaCGnj1XterhzR2w62poTGg2HHXOp1zDd3foNBY4kvrUApjN4rJZUg975G6YGqIIRNw3ZINvgZRcMBJpxVSDXaZFgVdWK2PA3HaR6yhs8agB+51jzWECHyj3YA1ZL1BUOw1dFnfJ7uy/lL1/FwV3eqd7vFrR707HAoJk0436FS5K1czKU4H1/SEO3pJ/irt2ZjS1V0bPKXggGfaO6xhaw11s4fJJO6AR02Eydfwcb6d383FvPr0PP1z+ngAHp1usQvOYKoBV7Pp/UNFO+Ih8fvJ9K/JP0JX6xw88IRfBpvQcD1QWIZ2yJwsFa1+yMT7gdqOjwJnesX+8E2OT6eVSc27hMtxNv8d+7zqDHOrIx4OoqpASduveE5tDSJhFrZfCWczVdGvQK0Cf2Md8rc2kxT610LipUBx7RyIReO0//xTmY3F7UmmfB3pj1FUTJYJ6YT62ud/H39/Ap7CNl9G9X/whJ4+hG0uquNQ29MpqGvUOFIpzvSKnRMeEyq2zsV+vk2WcMZkGwyqIeOiUNzADx3eSnEEMCmOxbJFT5jUVdLy0PSWrsLOy37MVEOeN+TvYrK9TntQUowsTIoSuGOmx1/MbbKRXni4zsLgUg+OqnUutSfEBapYjCns9gvSzSIP8QZ+awzcsu9AJu0y6R5H2y6P92y7sTk6vZ/54PGpKJzgivNvAAAA//8BAAD//yR4z29BBAAA\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvZmlsZV9uZXcuaHRtbA==\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvZmlsZV9uZXcuaHRtbA==\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/3SSb47TMBDFv/sUo0FIINGm3WURdGMfgQtQVDnxZOMqsY096R9VvTtymwQqxBdLjn7z3rznlMYewBqJlUElxO1adzolie0XVI6O0NiOysLYgxJl42MPPXHrjcTgEyPomq13EovMIbCOb8QSbRN3mUYlSuvCwMDnQBJbaww5BKd7kugDwkF3A0l0dLxt8H/Y2DjTl8vS2Hi93kY6XVGnsv933dOmLO4fxAQVD6JMJ54k8zlr4pQ8772ovePoO4TE544kHq3hdvO8WoUTQtDMFJ3EH9vjdrEttsufl/Wn9csVIXS6ptZ3hqJEetusn56XfGLwEZ5W68+rr4Ve7pN3CJF+DTaSAT2wb3w9JGDL2asfEkM/cN3CPwbjK6m/UkPelRzPyafnup85sI6kH5N8e3n/ihD9MUlcrxDGRkYpVGUxzSkx6omyJscU1UOfaah6y3OLSR8I8n0ss2IHFbtFiLbX8ZyFRxVRFrlpJcRkUKY62sCQYi2xiJSKfSoMNXroeLlPefZOzKgSIUR/Ou9YV7s0hA/4rjL4UfwBRWmbqHsa883/5dSGsSl0+rxx3tFrdrjjCuA3AAAA//8BAAD//0Es6wUcAwAA\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvbGF5b3V0Lmh0bWw=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvbGF5b3V0Lmh0bWw=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/4xVMXP0NBDt71cIFXwNsaBjwFYDdAyhSEN1o5PX9gZZMtqVw43xf2cs+/I5d5dMrvBa0r63T2+lc/nNr4+/PP3152+i497pQ3kJYGp9KHtgI2xnIgFXMnHz8KPUh9Kh/1t0EZpKqgiksG9VY0a0wRdogxQigqskdSGyTSyWBSnUhdCbHio5IrwMIbIUNngGz5V8wZq7qoYRLTzkwXcCPTIa90DWOKh+KL6Xb2lM4i7EHUmdXgCvkijaXUbHPNBPSrXIXToVNvSqwzqpYYjh3/MCZWQHepoKSqen5X2ep6ng9U38J9ZMMU3FCJEw+Hku1Qo6lGQjDiwo2s2eZ1LP/ySI5+KZpC7VmnDxcbWKzw6oA2C5N9YSqcYZLiyR/CwgL10QW63RxE30cVNcyb16+fNOltq6fwr1WR/KGkeBdSW9GeVu2INPUh/E+iuTy7MOGj5SOr1dzRkOhXWGqJKnEGuIxwYjsdSluexAagJaBJXK6FI5vCbY5drgG2ylXuNdwDRhIwqk30OLfp7f52rQgdTL8x0e8PVHeHMKiaXO4RPSE4FpQeo13gBKldzr4HVysX2170vEtuMv+wLlDvFq9n23p6nwgdHCcmSvZK46aTA+99IG78HykdhwIqm/9ScaloMyGH+7xytwIohHn/pj8A495MLL3GMePgU2blGQucSycEv4Qf+2chtn8YfpL/sRd9K+Wu9Cm1u1xru9yv12BHcLvmFCn4nw/nG9PTa5sWI/rnHUdzosrQMTl7+KnHAV3s/Lz2kqlos7z58DrLc2tMcax13F7e6r/D34HwAA//8BAAD//1aN3LcmBgAA\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvbG9naW4uaHRtbA==\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvbG9naW4uaHRtbA==\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/6SSzW6rQAxG9zyF5X3EXd8ySF10l0XfoBoYh1iav3pMUt6+moRESZt2UxaDhI8/HzCd4wOwMzi4f9g33SBt/+hoTuDobSkGfZo4bsooRLE27ZIECKT75AzmVBTBjsopGmxPLIJamUgN8k7eKn5qY/KukPZN52mi6PpnFzjCtrZ07fqsgcv1XWFNAnjI1OpmkjTnewag45hnBV0yGVT6UIRoAxmsJ0L2dqR98o7E4EtUEljSLHCuHqyfySDejRlTVEkeQeh9ZiF3b9U6PvTNH0WzLeWYxCGstrkcv8i+XpFfLR/J/TS1zENgvQZu0wR1oWvsoBEGjZssHKwst8lrbtfe7LmtGvV+/h4XhHdiA61vdf1FoOjiyaDjkr1d/scU6Qn7rj3jPcAnAAAA//8BAAD//xNoF86+AgAA\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvbmV0d29yay5odG1s\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvbmV0d29yay5odG1s\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/7RV227zKBC+jp9ixCry7kXrdHvQbmr7VRCGSUxCAAHO4e1/gQ85KK3a/vp9EQh88803wzCUnjtpA3jHK1I49MXGFw3z+PbyuPGkLoseUGd3kd7wLYZHab4ERu+l0TfQrAysUQhSVERjOBi3fQgNqbMyuPgj0g7zUmBcFHJ/CaVK+kCF3I97PpwUVvmOubXUy2d7zOusXBm3u7JaSRXQ0bgeDVcSlfAYhStcoxb1oBV6YFkMyxkAzAbBBylCW5GnxWJO6mwGkASnsR033xb2SGquJOqwLIvQDgAxAl6icSm17QKEk8WKBDwGAlwx7ysSBT5wo4MzioyxJdPl/6/zPMaU9+xU2hw022FFpgUCVjGOrVEC3bgO0pIayiKI+2I7j+5bUnun0exT2WSSfSOrYV5yYF1ooYtcBIIM0SBWyaiymHI75bjGI1edwCuxdTaLE8UaVNdieYt825jjKLiNBQV7pjqscrlja8whYVAMYBSkThtl0fP9jHvj7xFv/O+xcn+XlvszL6Svz+EwD+Kc0/QPPjzQ6I12Tk0e8x+dLtMnsMwFMCuIbJ+fKWhzcMzWnVPXNciN8pbp6uWTCnSK7ljg7ZfK8L/vCk1jvPj99KJlFNFPHIXcx34W29CgwDKNij6NzWlYFXJPGypvJP2brt9fA01rfPiC0fMHl/I62MWcjO2PKsOZopE+hph8WRbaP+gr0k++7rgBJ9dtIHBN9JrSUTIAo7mSfFsRa407nujQmylXyPTf/xBoHa4qsmF71j8qy3cCddotCzY5TsMMMpjekOg/NPTyKUmd/Pwi5eftqfxDkw60L1hkYmzLLcYwlk/2+G726FbKHJbQSiFQ5+MFhKHa4fK76LHPfdAXV/YO5nX+EeR2eazcYR7VDsIbI04RncYY8lTbV+nKsp4xddYpb+m8aLxYqM9VNCCTy4nuFwAAAP//AQAA//9PV68ZYAgAAA==\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvcmVwbGF5Lmh0bWw=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvcmVwbGF5Lmh0bWw=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/7yWzW7jNhCAz9FTEFy3kpDEToEeClsSsLfeWrQ99BBAoMSRxYSmtNTYG8PVuxdDSv6L481ui704Cjl/nPlmyESqDVMy5YXkWZAUdpYFSdXYFRMlqsakfGah1WLL2QqwbmTK26ZD7nT8Tk7inKGwS8CU54UW5pmzUouuSzlt5g+ciTU2ZbNqNSCkvKkqckfOB7n6Z555e8lMqg1FoUDLDjALEg1LMDIrRKfKZDb8FyQoCg3012YJ1pmPmK2tniczrLMEZZYo066R4baFlCO8IGdGrCDlzlbuVfK11ZxthF5Dyne76WG1708Ocl82Bm2jeZbMyPgM7cG9z8+7XXvxY7cWPk396ltu2SW/vzYdvttr7Yp36pPW3nXQ2ZjwYx+1khLMqZc/YNUgfJTSnvsqtQKDuWr7nr/D0LqDVyZozWvPDohcwqUGIcEy4tkgKxvd2HRpxTaLGqO3bN0Bwxo6YJ479llhzdrWNi/bOJmRUsZ+NEXXLoJEsNpClfIPnDWm1Kp8TvkkCj9gkXs3YTzFZrnUEMU86+rm86xWEpKZoDhPiXW9s1fkrMOthpRL1VEYc9MY4Fmw21lhlsAmz3eTzTz1lXIafe9qH1Dxd7vJc9/78gdU/4CxvaYyEl7uJvlmnk42fR8wxhj13NuQeAe5t3qU+Em++afG1bV+cE3Ldjswklw5bgKWoBwVtOiQ05Jv70sZtYBra5iQMkcbYa26u3AIKYx5dkvpvFaRQd8XIqdcj3ZizlAhpdlvMqk62ufZ30ONfFRD1I738SwH7r8A3BIwb4UVq+49x3PwuPG4BAzvQtJ2p3QmrpIzar2Bybg9gHLOCXOcvEnJdUIoym/G4yijklL4Co6vZGOfsu8ERnAKxhtk7HaqYvCJHQ10xvjvv/35F6ezv+aGbtRvAocUw7vQ6X8NOu4Kv8JO626Ei/AQO+xb4XGB/k/0/Gd4Dln7TvS8Y6rsN/1DjN5Hw+1AabwXWi3NvASDYBfX78/x1XZ4p+0z7q+4c/VuXawUcjYmtUDDCjT3rVUrYbecjeqvb8uzO9ELhPF0I3QUehHKc5B0rTDjgVbCLpW511Dh/KeHh/aF6kwCXxvXaVhSWSjxakRexEc01oeA279/3e+4FyRdaVWLWVCtjX9hnoHQFE/xLriZuI9pKywY7CKOlsfTShkZcXceHk9BlHU0molI6UZV0cSjNBWINuIDQZLHbp8xNu5bWDUb+HgmtQhubnrQHZxJn1m7O1cJbnr6GNiuhO5gEfTB4ZRDszTF011rId7R82EjLKNWTTnNhkdaogFxXLCQSA2HaoXHjRwOpQ+PWLZqWePis5JYz395+CFkjXmG7bpNQ7T5Rui8rI1Ygm/ZR85vWwu3/JHHIWu1KKFutASbhm7wOfTDzA+qITh5KbgxFen4cTncCx4cbKF/FY8eRmUaQ2E2TpDwQ7iHMByLMsLxyNE+8rGkUbwYy6BFB4swk6Bpfhy5odnBF/SpqojO0lSsKZ7SlDfFExHvC8QuUigqBBtR4WJnYuTlSN5CC0Z6GSdCP2/DcVqdAyM3RIiBF8xd1tMrTYGSDX2x8GobodPJFK1aRYMatWtM26qKaDfl3DXFwcEXMN83xisNQoVT0Lcboa/0Vh/QqB5HwL8AAAD//wEAAP//O8CrWS8PAAA=\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvcmVwbGF5X2RpcmVjdC5odG1s\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvcmVwbGF5X2RpcmVjdC5odG1s\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/8xRy27DIBA8l69A1KoSKTI9J2t+xcKGxih+IFijRpR/rzZucqjSey+wj9mZgQXjEnemEZ0RikEX5OP8WMLEdY9umRuRc0153eno+nqrtmsYSxF8sjgs5jdmq1K/H3WMjaBe+y5uarc4WD/qa2tcsD2SOuputIpBrz3xq+eE/G3uoj/97QjknYDlHPR8try6HKp0bLaJs8VS2Muj114OVZuOTZWozDkHDApwUDlXl1KOIHFQgEaBm/2KHK/eNgLtJwo+68nSywkoeNLjuqVt+hpwou9RIGlUYlCkaWdTCrvfzw36Jf4bhyB/tsJAkjkKYh+cR8WqnXh9ssl9HdducrjbnxjIO5iBNC6pbwAAAP//AQAA///vqKAEcQIAAA==\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy90cGwvdXNlYWdlLmh0bWw=\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy90cGwvdXNlYWdlLmh0bWw=\"),\n\t\t\tMtime:   1448806296,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/6xUwW7jNhA9L79iwL3EQCBZzmJrEJJ6aBfbQ4sumvRUFAElji1uJVIhR3YMr4H21gL9gv2W/E0/IL9QkLIcJ21vRQ6RZx4fZ948Tq70BrQqeKXmvGR55dKS5T3UrfS+4M0bXv7oUa4xT/tnibe8zJKvWo2GHh9+x7XoG2vw8eGPI9BhyTwSbPVKQ0PUQ+/s/U6w+A8a6wkeHz5DXpX7fdLH6G2IHg55WpVHWG/dv8BC9AhjeRqvyn0n27aURjmrFQwenYdamvAVDseDX4dcOAZkoZNGrtGNZfk8HQnYix4XyTW6DToRGEEbQreSNZ41udFeE+QSGoergqe8vEbvtTXwrfYEH6J2Ml650bgF2bZADY6aOLwb0BNQ4+ywboAa7ceKEqZNxPkj20q3hA5W1nWXIwneE2jTDzQ1mq+sIahta13hUJWf8jRE4t0YSoduaEn3LUJtjdKkrfEJw3XUS+QjGe16LHhg57CR7YAFl58qDp52LRZ8qxU14s28v+flpSbocLzcgfYgwTqoErazw7n6DvtW7iblx18gp+6TaYgvtL9KvrNKr3bww4jzo+pKb8qJvxsB51om79/d/PXrbx++v76BXjrZSQ/SqBHToFTofJKngWXkGk0VS/0oN9LXTvcU6pR1o3GDoElM+FjmajB1kA4cbp0mvHB4N9szAIA0jZVZheBJOsp9L82kXByMqNoBeRnRehWOJsH1RcG3221SSa2GpLYdn+3ZKwA45WM6e3sVk89St1IpV/Bs8UUyD39imXFIU/BoVACFVqZkJpZZPBxsdLtGSqRSF1zySy75LGbSNOZ66ynxSBdcTckDe5WnoaHy2CucmkWjYswhDS4Ic8cOp6cZpIsmuANbfcSaoJE+eNsjSCKnq4HQB3dcDK4twqBEmoZ+8V52fYuh51S21dClrfb0Za1VkS3ezh4fPj8bjK8b7CSIOGsWV4yAFzwsrhQByznrJTUg4IyZrZEE7GutxE/Z4urnAwsyCNgfWHC4kR2CANZL77fWqfDdITVWCXj/7oZNogII2EulxOSUi18uN7P94dIj/SO2fhYLkRbNU2S2PxyAnUbyPzMzdnKQgNdh3TiU7bidw3C32jePD3/i+sxBV4ts+R8v9s30Yr+xp+caca/DwgrKM4Nb/2TzJ1rGXlvT7mCZjUu/k1Q3L9BimZ07ecHG/PFVnKfmy/nJftEhfwMAAP//AQAA//+CM/4q6AYAAA==\"),\n\t\t},\n\n\t\t_assestBase64Decode(\"L3Jlcy92ZXJzaW9u\"): {\n\t\t\tName:    _assestBase64Decode(\"L3Jlcy92ZXJzaW9u\"),\n\t\t\tMtime:   1478614292,\n\t\t\tContent: _assestGzipBase64decode(\"H4sIAAAJbogA/zLQM9UzAgAAAP//AQAA//9B6J7GBQAAAA==\"),\n\t\t},\n\t},\n}\n"
  },
  {
    "path": "serve/auth.go",
    "content": "package serve\n\nimport (\n\t\"encoding/base64\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/hidu/goutils/str_util\"\n)\n\nvar proxyAuthorizatonHeader = \"Proxy-Authorization\"\n\nfunc getAuthorInfo(req *http.Request) *User {\n\tdefaultInfo := new(User)\n\tauthheader := strings.SplitN(req.Header.Get(proxyAuthorizatonHeader), \" \", 2)\n\tif len(authheader) != 2 || authheader[0] != \"Basic\" {\n\t\treturn defaultInfo\n\t}\n\tuserpassraw, err := base64.StdEncoding.DecodeString(authheader[1])\n\tif err != nil {\n\t\treturn defaultInfo\n\t}\n\tuserpass := strings.SplitN(string(userpassraw), \":\", 2)\n\tif len(userpass) != 2 {\n\t\treturn defaultInfo\n\t}\n\treturn &User{Name: userpass[0], PswMd5: str_util.StrMd5(userpass[1]), Psw: userpass[1]}\n}\n\nfunc (ser *ProxyServe) checkUserLogin(userInfo *User) bool {\n\tif userInfo == nil || ser.Users == nil {\n\t\treturn false\n\t}\n\n\tif userInfo.SkipCheckPsw {\n\t\treturn true\n\t}\n\n\tif user, has := ser.Users[userInfo.Name]; has {\n\t\treturn user.PswMd5 == userInfo.PswMd5\n\t}\n\treturn false\n}\n\n// (ser.conf.AuthType == AuthType_Basic && !ser.CheckUserLogin(reqCtx.User))\nfunc (ser *ProxyServe) checkHTTPAuth(reqCtx *requestCtx) bool {\n\tswitch ser.conf.AuthType {\n\tcase authTypeNO:\n\t\treturn true\n\tcase authTypeBasic:\n\t\treturn ser.checkUserLogin(reqCtx.User)\n\tcase authTypeBasicWithAny:\n\t\treturn reqCtx.User.Name != \"\"\n\tcase authTypeBasicTry:\n\t\tif reqCtx.ClientSession.RequestNum == 1 {\n\t\t\treturn reqCtx.User.Name != \"\"\n\t\t}\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "serve/broadcast.go",
    "content": "package serve\n\nimport (\n\t\"strconv\"\n)\n\n// broadcastReq broadcast request to user's browser\nfunc (ser *ProxyServe) broadcastReq(reqCtx *requestCtx) bool {\n\treq := reqCtx.Req\n\tdata := make(map[string]any)\n\tdata[\"docid\"] = strconv.Itoa(reqCtx.Docid)\n\tdata[\"sid\"] = reqCtx.SessionID % 10000\n\tdata[\"host\"] = req.Host\n\tdata[\"client_ip\"] = req.RemoteAddr\n\turlPath := req.URL.Path\n\tif req.URL.RawQuery != \"\" {\n\t\turlPath += \"?\" + req.URL.RawQuery\n\t}\n\tdata[\"path\"] = urlPath\n\tdata[\"url\"] = req.URL.String()\n\tif req.Method == \"CONNECT\" && !ser.conf.SslOn {\n\t\tdata[\"path\"] = \"https req,unknow path\"\n\t}\n\tdata[\"method\"] = req.Method\n\tdata[\"replay\"] = reqCtx.IsRePlay\n\n\thasSend := ser.wsSer.broadcastReq(req, reqCtx, data)\n\treturn hasSend\n}\n"
  },
  {
    "path": "serve/certs.go",
    "content": "package serve\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc newCaCert(caCert []byte, caKey []byte) (tls.Certificate, error) {\n\tca, err := tls.X509KeyPair(caCert, caKey)\n\tif err != nil {\n\t\tlog.Println(\"NewCaCert error:\", err)\n\t\treturn ca, err\n\t}\n\tif ca.Leaf, err = x509.ParseCertificate(ca.Certificate[0]); err != nil {\n\t\tlog.Println(\"NewCaCert error:\", err)\n\t\treturn ca, err\n\t}\n\tlog.Println(\"NewCaCert Ok\")\n\treturn ca, nil\n}\n\n// getSslCert get user's caCert or use the default buildin\nfunc getSslCert(caCertPath string, caKeyPath string) (ca tls.Certificate, err error) {\n\tif caCertPath == \"\" {\n\t\tcaCert := Assest.GetContent(\"/res/private/client_cert.pem\")\n\t\tcaKey := Assest.GetContent(\"/res/private/server_key.pem\")\n\t\treturn newCaCert([]byte(caCert), []byte(caKey))\n\t}\n\tcert, err := os.ReadFile(caCertPath)\n\tif err != nil {\n\t\treturn ca, err\n\t}\n\tkey, err := os.ReadFile(caKeyPath)\n\tif err != nil {\n\t\treturn ca, err\n\t}\n\treturn newCaCert(cert, key)\n}\n"
  },
  {
    "path": "serve/config.go",
    "content": "package serve\n\nimport (\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/Unknwon/goconfig\"\n\t\"github.com/hidu/goutils/fs\"\n\t\"github.com/hidu/goutils/str_util\"\n)\n\n// Config  pproxy's config\ntype Config struct {\n\tPort         int\n\tAdminPort    int\n\tTitle        string\n\tNotice       string\n\tAuthType     int\n\tDataDir      string\n\tFileDir      string\n\tResponseSave int\n\tSessionView  int\n\tDataStoreDay float64\n\tParentProxy  *url.URL\n\n\tSslOn bool\n\n\tSslCert tls.Certificate\n\n\tModifyRequest bool\n}\n\nconst (\n\tauthTypeNO           = 0\n\tauthTypeBasic        = 1\n\tauthTypeBasicWithAny = 2\n\tauthTypeBasicTry     = 3\n\n\tresponseSaveAll      = 0\n\tresponseSaveHasBroad = 1 // has show\n\n\tsessionViewALL      = 0\n\tsessionViewIPOrUser = 1\n)\n\n// User user struct\ntype User struct {\n\tName         string\n\tPsw          string\n\tPswMd5       string\n\tIsAdmin      bool\n\tSkipCheckPsw bool\n}\n\n// String string format\nfunc (u *User) String() string {\n\treturn fmt.Sprintf(\"Name:%s,Psw:%s,isAdmin:%v,SkipCheckPsw:%v\", u.Name, u.Psw, u.IsAdmin, u.SkipCheckPsw)\n}\n\n// ConfigString one line in file\nfunc (u *User) ConfigString() string {\n\treturn fmt.Sprintf(\"name:%s\\tpsw:%s\\tis_admin:%v\\tpsw_md5:%s\", u.Name, u.Psw, u.IsAdmin, u.PswMd5)\n}\n\nconst (\n\tcontentEncoding = \"Content-Encoding\"\n)\n\n// \"0:no auth | 1:basic auth | 2:basic auth with any name\"\n\n// GetVersion get current version\nfunc GetVersion() string {\n\treturn Assest.GetContent(\"res/version\")\n}\n\n// GetDemoConf get the demo config\nfunc GetDemoConf() string {\n\treturn strings.TrimSpace(Assest.GetContent(\"res/conf/demo.conf\"))\n}\n\nfunc (u *User) isPswEq(psw string) bool {\n\treturn u.PswMd5 == str_util.StrMd5(psw)\n}\n\n// LoadConfig load the pproxy's config\nfunc LoadConfig(confPath string) (*Config, error) {\n\tgconf, err := goconfig.LoadConfigFile(confPath)\n\tif err != nil {\n\t\tlog.Println(\"load config\", confPath, \"failed,err:\", err)\n\t\treturn nil, err\n\t}\n\tconfig := new(Config)\n\tconfig.Port = gconf.MustInt(goconfig.DEFAULT_SECTION, \"port\", 8080)\n\tconfig.AdminPort = gconf.MustInt(goconfig.DEFAULT_SECTION, \"adminPort\", 0)\n\n\tif config.AdminPort == 0 {\n\t\tconfig.AdminPort = config.Port\n\t}\n\n\tconfig.DataStoreDay = gconf.MustFloat64(goconfig.DEFAULT_SECTION, \"dataStoreDay\", 0)\n\tif config.DataStoreDay < 0 {\n\t\tlog.Println(\"wrong DataStoreDay,skip\")\n\t\tconfig.DataStoreDay = 0\n\t}\n\n\tconfig.Title = gconf.MustValue(goconfig.DEFAULT_SECTION, \"title\")\n\tconfig.Notice = gconf.MustValue(goconfig.DEFAULT_SECTION, \"notice\")\n\tconfig.DataDir = gconf.MustValue(goconfig.DEFAULT_SECTION, \"dataDir\", \"../data/\")\n\n\tconfig.FileDir = gconf.MustValue(goconfig.DEFAULT_SECTION, \"fileDir\", \"../file/\")\n\n\t_authType := strings.ToLower(gconf.MustValue(goconfig.DEFAULT_SECTION, \"authType\", \"none\"))\n\tauthTypes := map[string]int{\"none\": 0, \"basic\": 1, \"basic_any\": 2, \"basic_try\": 3, \"try_basic\": 3}\n\n\thasError := false\n\tif authType, has := authTypes[_authType]; has {\n\t\tconfig.AuthType = authType\n\t} else {\n\t\thasError = true\n\t\tlog.Println(\"conf error,unknow value authType:\", _authType)\n\t}\n\n\t_responseSave := strings.ToLower(gconf.MustValue(goconfig.DEFAULT_SECTION, \"responseSave\", \"all\"))\n\tresponseSaveMap := map[string]int{\"all\": 0, \"only_broadcast\": 1}\n\n\tif responseSave, has := responseSaveMap[_responseSave]; has {\n\t\tconfig.ResponseSave = responseSave\n\t} else {\n\t\thasError = true\n\t\tlog.Println(\"conf error,unknow value responseSave:\", _authType)\n\t}\n\n\t_sessionView := strings.ToLower(gconf.MustValue(goconfig.DEFAULT_SECTION, \"sessionView\", \"all\"))\n\tsessionViewMap := map[string]int{\"all\": 0, \"ip_or_user\": 1}\n\n\tif sessionView, has := sessionViewMap[_sessionView]; has {\n\t\tconfig.SessionView = sessionView\n\t} else {\n\t\thasError = true\n\t\tlog.Println(\"conf error,unknow value responseSave:\", _authType)\n\t}\n\n\tparentProxy := gconf.MustValue(goconfig.DEFAULT_SECTION, \"parentProxy\", \"\")\n\tif parentProxy != \"\" {\n\t\t_urlObj, err := url.Parse(parentProxy)\n\t\tif err != nil || _urlObj.Scheme != \"http\" {\n\t\t\thasError = true\n\t\t\tlog.Println(\"parentProxy wrong,must http proxy\")\n\t\t} else {\n\t\t\tconfig.ParentProxy = _urlObj\n\t\t}\n\t}\n\tconfig.SslOn = gconf.MustValue(goconfig.DEFAULT_SECTION, \"ssl\", \"off\") == \"on\"\n\tif config.SslOn {\n\t\t_sslClientCert := gconf.MustValue(goconfig.DEFAULT_SECTION, \"ssl_client_cert\", \"\")\n\t\t_sslServerKey := gconf.MustValue(goconfig.DEFAULT_SECTION, \"ssl_server_key\", \"\")\n\t\tcert, err := getSslCert(_sslClientCert, _sslServerKey)\n\t\tif err != nil {\n\t\t\thasError = true\n\t\t\tlog.Println(\"ssl ca config error:\", err)\n\t\t} else {\n\t\t\tconfig.SslCert = cert\n\t\t}\n\t}\n\n\tconfig.ModifyRequest = gconf.MustValue(goconfig.DEFAULT_SECTION, \"modifyRequest\", \"on\") == \"on\"\n\n\tif hasError {\n\t\treturn config, errors.New(\"config error\")\n\t}\n\n\treturn config, nil\n}\n\ntype configHosts map[string]string\n\n// loadHosts 读取host配置文件\nfunc loadHosts(confPath string) (hosts configHosts, err error) {\n\thosts = make(configHosts)\n\tif !fs.FileExists(confPath) {\n\t\treturn\n\t}\n\thostsByte, err := fs.FileGetContents(confPath)\n\tif err != nil {\n\t\tlog.Println(\"load hosts_file failed:\", confPath, err)\n\t\treturn nil, err\n\t}\n\thostsArr := str_util.LoadText2Slice(string(hostsByte))\n\tfor _, v := range hostsArr {\n\t\tif len(v) != 2 {\n\t\t\tlog.Println(\"hosts file line wrong,ignore,\", v)\n\t\t\tcontinue\n\t\t}\n\t\thosts[v[0]] = v[1]\n\t}\n\treturn\n}\n\nfunc loadUsers(confPath string) (users map[string]*User, err error) {\n\tusers = make(map[string]*User)\n\tif !fs.FileExists(confPath) {\n\t\treturn\n\t}\n\tuserInfoByte, err := fs.FileGetContents(confPath)\n\tif err != nil {\n\t\tlog.Println(\"load user file failed:\", confPath, err)\n\t\treturn\n\t}\n\tlines := str_util.LoadText2SliceMap(string(userInfoByte))\n\tfor _, line := range lines {\n\t\tname, has := line[\"name\"]\n\t\tif !has || name == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif _, has := users[name]; has {\n\t\t\tlog.Println(\"dup name in users:\", name, line)\n\t\t\tcontinue\n\t\t}\n\n\t\tuser := new(User)\n\t\tuser.Name = name\n\t\tif val, has := line[\"is_admin\"]; has && (val == \"admin\" || val == \"true\") {\n\t\t\tuser.IsAdmin = true\n\t\t}\n\t\tif val, has := line[\"psw_md5\"]; has {\n\t\t\tuser.PswMd5 = val\n\t\t}\n\n\t\tif user.PswMd5 == \"\" {\n\t\t\tif val, has := line[\"psw\"]; has {\n\t\t\t\tuser.Psw = val\n\t\t\t\tuser.PswMd5 = str_util.StrMd5(val)\n\t\t\t}\n\t\t}\n\t\tusers[user.Name] = user\n\t}\n\treturn\n}\n\nfunc (config *Config) getTransport() *http.Transport {\n\tif config.ParentProxy == nil {\n\t\treturn nil\n\t}\n\ttr := &http.Transport{\n\t\tProxy: func(req *http.Request) (*url.URL, error) {\n\t\t\tif config.ParentProxy.User.Username() == \"pass\" {\n\t\t\t\tuser := getAuthorInfo(req)\n\t\t\t\turlTmp, err := url.Parse(config.ParentProxy.String())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\turlTmp.User = url.UserPassword(user.Name, user.Psw)\n\t\t\t\treturn urlTmp, nil\n\t\t\t}\n\t\t\treturn config.ParentProxy, nil\n\t\t},\n\t}\n\treturn tr\n}\n"
  },
  {
    "path": "serve/init.go",
    "content": "package serve\n\n// 系统版本\nvar PproxyVersion string\n\nfunc init() {\n\tPproxyVersion = GetVersion()\n}\n"
  },
  {
    "path": "serve/kvStore.go",
    "content": "package serve\n\nimport (\n\t\"time\"\n\n\t\"github.com/boltdb/bolt\"\n\t\"github.com/hidu/goutils/time_util\"\n)\n\ntype KV_TBALE_NAME_TYPE string\n\nconst (\n\tKV_TABLE_REQ KV_TBALE_NAME_TYPE = \"req\"\n\tKV_TABLE_RES KV_TBALE_NAME_TYPE = \"res\"\n)\n\ntype kvStore struct {\n\tdbPath string\n\tdb     *bolt.DB\n\ttables map[KV_TBALE_NAME_TYPE]*kvStoreTable\n}\n\ntype kvStoreTable struct {\n\tname KV_TBALE_NAME_TYPE\n\tkv   *kvStore\n}\n\ntype StoreType struct {\n\tNow  int64  `json:\"now\"`\n\tData KvType `json:\"data\"`\n}\n\nfunc newStoreType(data map[string]any) *StoreType {\n\treturn &StoreType{Now: time.Now().Unix(), Data: data}\n}\n\nfunc newKvStore(dbPath string) (kv *kvStore, err error) {\n\tkv = &kvStore{\n\t\tdbPath: dbPath,\n\t}\n\tkv.db, err = bolt.Open(kv.dbPath, 0600, nil)\n\tif err != nil {\n\t\treturn\n\t}\n\tkv.tables = make(map[KV_TBALE_NAME_TYPE]*kvStoreTable)\n\n\tkv.initTable(KV_TABLE_REQ)\n\tkv.initTable(KV_TABLE_RES)\n\n\treturn\n}\n\nfunc (kv *kvStore) initTable(name KV_TBALE_NAME_TYPE) {\n\tkv.tables[name] = newkvStoreTable(name, kv)\n}\n\nfunc (kv *kvStore) GetkvStoreTable(name KV_TBALE_NAME_TYPE) (tb *kvStoreTable) {\n\tif tb, has := kv.tables[name]; has {\n\t\treturn tb\n\t}\n\treturn nil\n}\n\nfunc (kv *kvStore) Gc(max_life int64) {\n\tfor _, tb := range kv.tables {\n\t\ttb.Gc(max_life)\n\t}\n}\n\nfunc (kv *kvStore) StartGcTimer(sec int64, max_life int64) {\n\tif max_life < 1 {\n\t\treturn\n\t}\n\ttime_util.SetInterval(func() {\n\t\tkv.Gc(max_life)\n\t}, sec)\n}\n\nfunc newkvStoreTable(name KV_TBALE_NAME_TYPE, kv *kvStore) *kvStoreTable {\n\ttb := &kvStoreTable{\n\t\tname: name,\n\t\tkv:   kv,\n\t}\n\ttb.kv.db.Update(func(tx *bolt.Tx) error {\n\t\t_, err := tx.CreateBucketIfNotExists([]byte(name))\n\t\treturn err\n\t})\n\treturn tb\n}\n\nfunc (tb *kvStoreTable) Save(key []byte, val *StoreType) error {\n\terr := tb.kv.db.Update(func(tx *bolt.Tx) error {\n\t\tbk, _ := tx.CreateBucketIfNotExists([]byte(tb.name))\n\t\treturn bk.Put(key, dataEncode(val))\n\t})\n\treturn err\n}\n\nfunc (tb *kvStoreTable) Get(key []byte) (val *StoreType, err error) {\n\terr = tb.kv.db.View(func(tx *bolt.Tx) error {\n\t\tbk := tx.Bucket([]byte(tb.name))\n\t\tbs := bk.Get(key)\n\t\tif len(bs) > 0 {\n\t\t\treturn dataDecode(bs, &val)\n\t\t}\n\t\treturn nil\n\t})\n\treturn\n}\n\nfunc (tb *kvStoreTable) Del(key []byte) (err error) {\n\terr = tb.kv.db.Update(func(tx *bolt.Tx) error {\n\t\tbk := tx.Bucket([]byte(tb.name))\n\t\treturn bk.Delete(key)\n\t})\n\treturn\n}\n\nfunc (tb *kvStoreTable) Gc(gc_life int64) {\n\tif gc_life < 1 {\n\t\treturn\n\t}\n\tmax_time := time.Now().Unix() - gc_life\n\tvar val *StoreType\n\ttb.kv.db.View(func(tx *bolt.Tx) error {\n\t\tbk := tx.Bucket([]byte(tb.name))\n\t\tbk.ForEach(func(k, v []byte) error {\n\t\t\tdataDecode(v, &val)\n\t\t\tif val != nil && val.Now < max_time {\n\t\t\t\ttb.Del(k)\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "serve/proxy.go",
    "content": "package serve\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/elazarl/goproxy\"\n)\n\ntype HttpProxy struct {\n\tGoProxy            *goproxy.ProxyHttpServer\n\tser                *ProxyServe\n\tctxs               map[string]*requestCtx\n\tmu                 sync.RWMutex\n\tgoproxyMitmConnect *goproxy.ConnectAction\n}\n\nfunc NewHttpProxy(ser *ProxyServe) *HttpProxy {\n\tproxy := new(HttpProxy)\n\tproxy.ser = ser\n\tproxy.GoProxy = goproxy.NewProxyHttpServer()\n\ttr := ser.conf.getTransport()\n\tif tr != nil {\n\t\tproxy.GoProxy.Tr = tr\n\t}\n\tproxy.ctxs = make(map[string]*requestCtx)\n\tif proxy.ser.conf.SslOn {\n\t\tproxy.goproxyMitmConnect = &goproxy.ConnectAction{\n\t\t\tAction:    goproxy.ConnectMitm,\n\t\t\tTLSConfig: goproxy.TLSConfigFromCA(&proxy.ser.conf.SslCert),\n\t\t}\n\t\tproxy.GoProxy.OnRequest().HandleConnectFunc(proxy.httpsHandle)\n\t}\n\tproxy.GoProxy.OnRequest().DoFunc(my_requestHanderFunc)\n\tproxy.GoProxy.OnResponse().DoFunc(proxy.onResponse)\n\treturn proxy\n}\n\nfunc my_requestHanderFunc(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {\n\tlog.Println(\"trace_my_requestHanderFunc call url:\", r.URL.String())\n\treturn r, nil\n}\n\nconst PROXY_CTX_NAME = \"X-PPROXY-CTX-ID\"\n\nfunc (proxy *HttpProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {\n\t// \tfmt.Println(\"call url:\",req.URL.String())\n\tproxy.GoProxy.ServeHTTP(rw, req)\n}\n\nfunc (proxy *HttpProxy) httpsHandle(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {\n\tlog.Println(\"https conn\", host, ctx.Req.URL.String())\n\treturn proxy.goproxyMitmConnect, host\n}\n\nfunc (proxy *HttpProxy) RoundTrip(ctx *requestCtx) {\n\tsid := strconv.FormatInt(ctx.SessionID, 10)\n\tctx.Req.Header.Set(PROXY_CTX_NAME, sid)\n\tfunc() {\n\t\tproxy.mu.Lock()\n\t\tdefer proxy.mu.Unlock()\n\t\tproxy.ctxs[sid] = ctx\n\t}()\n\n\tdefer func() {\n\t\tproxy.mu.Lock()\n\t\tdefer proxy.mu.Unlock()\n\t\tif _, has := proxy.ctxs[sid]; has {\n\t\t\tdelete(proxy.ctxs, sid)\n\t\t}\n\t}()\n\n\tif ctx.Req.Header.Get(\"Upgrade\") != \"\" {\n\t\tproxy.roundTripUpgrade(ctx)\n\t\treturn\n\t}\n\tproxy.ServeHTTP(ctx.Rw, ctx.Req)\n}\n\nfunc (proxy *HttpProxy) getReqCtx(req *http.Request) *requestCtx {\n\tsid := req.Header.Get(PROXY_CTX_NAME)\n\tif sid == \"\" {\n\t\treturn nil\n\t}\n\tproxy.mu.RLock()\n\tdefer proxy.mu.RUnlock()\n\tif ctx, has := proxy.ctxs[sid]; has {\n\t\treturn ctx\n\t}\n\treturn nil\n}\n\nfunc (proxy *HttpProxy) onResponse(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {\n\tif resp == nil || resp.Request == nil {\n\t\treturn resp\n\t}\n\treqCtx := proxy.getReqCtx(resp.Request)\n\n\tif reqCtx != nil {\n\t\treqCtx.saveResponse(resp)\n\t}\n\treturn resp\n}\n\nfunc (proxy *HttpProxy) roundTripUpgrade(ctx *requestCtx) (err error) {\n\t// save it,so we know it has been closed\n\tdefer func() {\n\t\tresp := &http.Response{\n\t\t\tRequest: ctx.Req,\n\t\t\tHeader:  make(http.Header),\n\t\t\tBody:    nil,\n\t\t}\n\t\tctx.saveResponse(resp)\n\t}()\n\n\treqDump, err := httputil.DumpRequest(ctx.Req, false)\n\tif err != nil {\n\t\tctx.Msg = \"dump req failed:\" + err.Error()\n\t\treturn\n\t}\n\tctx.SetTimePoint(\"startDial\")\n\tdia, err := net.Dial(\"tcp\", ctx.DestAddr())\n\tif err != nil {\n\t\tctx.Msg = \"dia connect \" + ctx.DestAddr() + \" failed!\" + err.Error()\n\t\treturn\n\t}\n\tdefer dia.Close()\n\t_, err = dia.Write(reqDump)\n\tif err != nil {\n\t\treturn\n\t}\n\n\thijack, _ := ctx.Rw.(http.Hijacker)\n\tconn, _, _ := hijack.Hijack()\n\n\terrc := make(chan error, 2)\n\n\tcp := func(dst io.Writer, src io.Reader) {\n\t\t_, err := io.Copy(dst, src)\n\t\terrc <- err\n\n\t\ttime.AfterFunc(3*time.Second, func() {\n\t\t\tdia.Close()\n\t\t\tconn.Close()\n\t\t})\n\t}\n\n\tgo cp(dia, conn)\n\tgo cp(conn, dia)\n\t<-errc\n\treturn\n}\n"
  },
  {
    "path": "serve/reqCtx.go",
    "content": "package serve\n\nimport (\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// requestCtx  一次http请求的数据结构\ntype requestCtx struct {\n\tRemoteAddr string\n\tReq        *http.Request\n\tRw         http.ResponseWriter\n\n\tHost string // eg www.baidu.com\n\tPort int    // eg 80\n\n\tUser     *User\n\tDocid    int\n\tIsRePlay bool\n\n\tSessionID     int64\n\tHasBroadcast  bool\n\tFormPost      *url.Values\n\tClientSession *clientSession\n\n\tOriginURL string\n\tlogData   map[any]any\n\tMsg       string\n\n\tser           *ProxyServe\n\tstartTime     time.Time\n\ttimeDurations map[string]time.Duration\n\thasPrint      bool\n}\n\n// NewRequestCtx 构建一个新的请求\nfunc NewRequestCtx(ser *ProxyServe, rw http.ResponseWriter, req *http.Request) *requestCtx {\n\tctx := &requestCtx{}\n\tctx.Req = req\n\tctx.ser = ser\n\tctx.Rw = rw\n\tctx.SessionID = ser.reqNum\n\n\tctx.logData = make(map[any]any)\n\tctx.timeDurations = make(map[string]time.Duration)\n\n\tctx.FormPost = &url.Values{}\n\tctx.init()\n\tctx.startTime = time.Now()\n\treturn ctx\n}\n\nfunc (ctx *requestCtx) init() {\n\tif ctx.Req == nil {\n\t\treturn\n\t}\n\tfixRequest(ctx.Req)\n\treq := ctx.Req\n\tctx.Host, ctx.Port, _ = getHostPortFromReq(req)\n\n\tctx.User = getAuthorInfo(req)\n\tctx.FormPost = getPostData(req)\n\n\tctx.OriginURL = req.URL.String()\n\tctx.IsRePlay = len(req.Header.Get(REPLAY_FLAG)) > 0\n\tctx.SetLog(\"url\", req.URL.String())\n\n\tctx.RemoteAddr = req.RemoteAddr\n\n\tif _replayAddr := req.Header.Get(REPLAY_REMOTEADDR); _replayAddr != \"\" {\n\t\tctx.RemoteAddr = _replayAddr\n\t}\n\tif _replayUser := req.Header.Get(REPLAY_USER_NAME); _replayUser != \"\" {\n\t\tctx.User = &User{Name: _replayUser, SkipCheckPsw: true}\n\t}\n\tctx.Docid = ctx.getNewDocid()\n\tctx.ser.regirestReq(ctx)\n}\n\nfunc fixRequest(req *http.Request) {\n\tif req.Method != \"CONNECT\" && !req.URL.IsAbs() {\n\t\turlOrigin := req.URL.String()\n\t\turlStr := \"http://\" + req.Host + req.URL.Path\n\t\tif req.URL.RawQuery != \"\" {\n\t\t\turlStr += \"?\" + req.URL.RawQuery\n\t\t}\n\t\tvar err error\n\t\treq.URL, err = url.Parse(urlStr)\n\t\tif err != nil {\n\t\t\tlog.Println(\"fix url failed,originUrl:\", urlOrigin, \"err:\", err)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (ctx *requestCtx) IsLocalRequest() bool {\n\tisLocalReq := ctx.Port == ctx.ser.conf.Port\n\tif isLocalReq {\n\t\tisLocalReq = IsLocalIP(ctx.Host)\n\t}\n\treturn isLocalReq\n}\n\nfunc (ctx *requestCtx) GetIp() string {\n\thostInfo := strings.Split(ctx.RemoteAddr, \":\")\n\treturn hostInfo[0]\n}\n\nfunc (ctx *requestCtx) PrintLog() {\n\treqID := 0\n\tif ctx.ClientSession != nil {\n\t\treqID = ctx.ClientSession.RequestNum\n\t}\n\tlog.Println(\n\t\t\"session_id:\", ctx.SessionID,\n\t\t\"remote:\", ctx.RemoteAddr,\n\t\t\"reqId:\", reqID,\n\t\t\"docid:\", ctx.Docid,\n\t\t\"uname:\", ctx.User.Name,\n\t\t\"broadcast:\", ctx.HasBroadcast,\n\t\t\"startTime:\", ctx.startTime.Unix(),\n\t\t\"timeUsed:\", fmt.Sprintf(\"%.3fs\", time.Since(ctx.startTime).Seconds()),\n\t\t\"data:\", ctx.logData,\n\t\t\"times:\", ctx.timeDurations,\n\t)\n}\n\nfunc (ctx *requestCtx) RoundTrip() {\n\tdefer func() {\n\t\tctx.hasPrint = true\n\t\tctx.SetLog(\"logType\", \"defer\")\n\t\tctx.PrintLog()\n\t}()\n\n\ttime.AfterFunc(10*time.Second, func() {\n\t\tif !ctx.hasPrint {\n\t\t\tctx.SetLog(\"logType\", \"timeout10\")\n\t\t\tctx.PrintLog()\n\t\t}\n\t})\n\n\tremoveHeader(ctx.Req)\n\trewriteCode := ctx.ser.reqRewrite(ctx)\n\n\tctx.HasBroadcast = ctx.ser.broadcastReq(ctx)\n\n\t// reqDump, _ := httputil.DumpRequest(ctx.Req, true)\n\t//    fmt.Println(\"req dump3:\\n\",string(reqDump))\n\n\tctx.SetLog(\"js_rewrite_code\", rewriteCode)\n\n\tctx.saveRequestData()\n\t// 异步的会导致req.body dump不了，先暂时这样，对接口会有一些影响\n\t// \ttime.AfterFunc(1*time.Second, ctx.saveRequestData)\n\n\tif rewriteCode != 200 && rewriteCode != 304 {\n\t\tctx.badGateway(errors.New(\"rewrite failed\"))\n\t\treturn\n\t}\n\tctx.ser.proxy.RoundTrip(ctx)\n}\n\nfunc (ctx *requestCtx) badGateway(err error) {\n\tctx.SetLog(\"errMsg\", fmt.Sprintf(\"%s\", err))\n\tctx.Rw.WriteHeader(http.StatusBadGateway)\n\tctx.Rw.Write([]byte(\"pproxy error\"))\n}\n\nfunc (ctx *requestCtx) DestAddr() string {\n\treturn fmt.Sprintf(\"%s:%d\", ctx.Host, ctx.Port)\n}\n\nfunc (ctx *requestCtx) saveRequestData() {\n\tif ctx.ser.conf.ResponseSave == responseSaveAll ||\n\t\t(ctx.ser.conf.ResponseSave == responseSaveHasBroad && ctx.HasBroadcast) {\n\t\tlogdata := KvType{}\n\t\tlogdata[\"host\"] = ctx.Req.Host\n\t\tlogdata[\"schema\"] = ctx.Req.URL.Scheme\n\t\tlogdata[\"header\"] = map[string][]string(ctx.Req.Header)\n\t\tlogdata[\"url\"] = ctx.Req.URL.String()\n\t\tlogdata[\"url_origin\"] = ctx.OriginURL\n\t\tlogdata[\"path\"] = ctx.Req.URL.Path\n\t\t// \t\tlogdata[\"cookies\"] = ctx.Req.Cookies()\n\t\t// \t\tlogdata[\"now\"] = time.Now().Unix()\n\t\tlogdata[\"user\"] = ctx.User.Name\n\t\tlogdata[\"client_ip\"] = ctx.RemoteAddr\n\t\tlogdata[\"method\"] = ctx.Req.Method\n\t\tlogdata[\"form_get\"] = ctx.Req.URL.Query()\n\t\tlogdata[\"replay\"] = ctx.IsRePlay\n\t\tlogdata[\"msg\"] = ctx.Msg\n\t\tlogdata[\"id\"] = strconv.Itoa(ctx.Docid)\n\n\t\t// 当无普通form post表单数据的时候，比如可能body也有数据\n\t\t// 比如request 的content-type=application/json\n\t\tdumpBody := len(*ctx.FormPost) == 0\n\t\t//   fmt.Println(\"dumpBody\",dumpBody)\n\t\t// dumpBody=false\n\t\treqDump, errDump := httputil.DumpRequest(ctx.Req, dumpBody)\n\t\tif errDump != nil {\n\t\t\tctx.SetLog(\"dumpMsg\", fmt.Sprintf(\"dump request failed,%s\", errDump.Error()))\n\t\t\treqDump = []byte(fmt.Sprintf(\"dump failed,%s\", errDump.Error()))\n\t\t}\n\t\tlogdata[\"dump\"] = base64.StdEncoding.EncodeToString(reqDump)\n\t\t// \t\tbuf := forgetRead(&ctx.Req.Body)\n\t\t// \t\tlogdata[\"dump\"] = base64.StdEncoding.EncodeToString(buf.Bytes())\n\n\t\tlogdata[\"form_post\"] = ctx.FormPost\n\n\t\ttb := ctx.ser.mydb.GetkvStoreTable(KV_TABLE_REQ)\n\t\tdata := newStoreType(logdata)\n\t\terr := tb.Save(IntToBytes(ctx.Docid), data)\n\t\tif err != nil {\n\t\t\tlog.Println(\"save req failed:\", err)\n\t\t}\n\t}\n}\n\nfunc (ctx *requestCtx) saveResponse(res *http.Response) {\n\tif ctx.Docid < 1 || res == nil {\n\t\treturn\n\t}\n\tdata := KvType{}\n\tdata[\"now\"] = time.Now().Unix()\n\tdata[\"header\"] = map[string][]string(res.Header)\n\tdata[\"status\"] = res.StatusCode\n\tdata[\"content_length\"] = res.ContentLength\n\tdata[\"msg\"] = ctx.Msg\n\tdata[\"id\"] = strconv.Itoa(ctx.Docid)\n\n\tresDump, dumpErr := httputil.DumpResponse(res, false)\n\tif dumpErr != nil {\n\t\tlog.Println(\"dump res err\", dumpErr)\n\t\tresDump = []byte(\"dump res failed\")\n\t}\n\tdata[\"dump\"] = base64.StdEncoding.EncodeToString(resDump)\n\t//   data[\"cookies\"]=res.Cookies()\n\n\tbody := []byte(\"pproxy skip\")\n\tif res.Body != nil && res.ContentLength <= ctx.ser.MaxResSaveLength {\n\t\tbuf := forgetRead(&res.Body)\n\t\tif res.Header.Get(contentEncoding) == \"gzip\" {\n\t\t\tbody = []byte(gzipDocode(buf))\n\t\t} else {\n\t\t\tbody = buf.Bytes()\n\t\t}\n\t\tl := int64(len(body))\n\t\tif l > ctx.ser.MaxResSaveLength {\n\t\t\tbody = []byte(fmt.Sprintf(\"pproxy skip,body too large,[len=%d]\", l))\n\t\t}\n\t}\n\tdata[\"body\"] = base64.StdEncoding.EncodeToString(body)\n\n\ttb := ctx.ser.mydb.GetkvStoreTable(KV_TABLE_RES)\n\tstoreData := newStoreType(data)\n\terr := tb.Save(IntToBytes(ctx.Docid), storeData)\n\n\tlog.Println(\"save_res\", ctx.SessionID, \"docid=\", ctx.Docid, \"body_len=\", len(data[\"body\"].(string)), err)\n}\n\nfunc (ctx *requestCtx) SetLog(k, v any) {\n\tctx.logData[k] = v\n}\n\nfunc (ctx *requestCtx) SetTimePoint(key string) {\n\tctx.timeDurations[key] = time.Since(ctx.startTime)\n}\n\nfunc (ctx *requestCtx) getNewDocid() int {\n\tidStr := fmt.Sprintf(\"%s%d\", time.Now().Format(\"200601021504\"), ctx.ser.reqNum)\n\tid, err := parseDocID(idStr)\n\tif err == nil {\n\t\treturn id\n\t}\n\tlog.Println(\"GetNewDocid failed\", idStr, err)\n\treturn int(time.Now().UnixNano() + ctx.ser.reqNum)\n}\n"
  },
  {
    "path": "serve/req_modifer.go",
    "content": "package serve\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/hidu/goutils/fs\"\n\t\"github.com/robertkrimen/otto\"\n)\n\nvar rewriteJsTpl = Assest.GetContent(\"res/sjs/req_rewrite.js\")\n\n/*\n * request动态修改引擎\n * 使用javascript 来对请求进行修改\n */\ntype requestModifier struct {\n\tmu     sync.RWMutex\n\tjsVm   *otto.Otto\n\tjsFns  map[string]*otto.Value\n\tcanMod bool\n\tser    *ProxyServe\n}\n\nfunc NewRequestModifier(ser *ProxyServe) *requestModifier {\n\treqMod := &requestModifier{\n\t\tjsVm:  otto.New(),\n\t\tjsFns: make(map[string]*otto.Value),\n\t\tser:   ser,\n\t}\n\treturn reqMod\n}\n\nfunc (reqMod *requestModifier) getJsPath(name string) string {\n\tbaseName := fmt.Sprintf(\"%s/req_rewrite_%d\", reqMod.ser.configDir, reqMod.ser.conf.Port)\n\tif name == \"\" {\n\t\treturn fmt.Sprintf(\"%s.js\", baseName)\n\t}\n\treturn fmt.Sprintf(\"%s_%s.js\", baseName, name)\n}\n\nfunc (reqMod *requestModifier) tryLoadJs(name string) (err error) {\n\tjsContent, err := reqMod.getJsContent(name)\n\tif jsContent != \"\" && err == nil {\n\t\terr = reqMod.parseJs(jsContent, name, false)\n\t\tif err != nil {\n\t\t\tlog.Println(\"load rewrite js failed:\", err)\n\t\t\treturn err\n\t\t}\n\t\tlog.Println(\"load rewrite js[\", name, \"] suc\")\n\t}\n\treturn nil\n}\n\nfunc (reqMod *requestModifier) loadAllJs() error {\n\tif !reqMod.ser.conf.ModifyRequest {\n\t\tlog.Println(\"ignore requestModifier loadAllJs\")\n\t\treturn nil\n\t}\n\tnames := []string{\"\"}\n\tfor _, user := range reqMod.ser.Users {\n\t\tnames = append(names, user.Name)\n\t}\n\tfor _, name := range names {\n\t\terr := reqMod.tryLoadJs(name)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (reqMod *requestModifier) getJsContent(name string) (content string, err error) {\n\tjsPath := reqMod.getJsPath(name)\n\tif fs.FileExists(jsPath) {\n\t\tscript, err := os.ReadFile(jsPath)\n\t\tif err == nil {\n\t\t\treturn string(script), nil\n\t\t}\n\t\treturn \"\", err\n\t}\n\treturn \"\", nil\n}\n\nfunc (reqMod *requestModifier) CanMod() bool {\n\treturn reqMod.canMod\n}\n\nfunc (reqMod *requestModifier) parseJs(jsStr string, name string, save2File bool) error {\n\tjsStr = strings.TrimSpace(jsStr)\n\trewriteJs := strings.Replace(rewriteJsTpl, \"CUSTOM_JS\", jsStr, 1)\n\trewriteJs = strings.Replace(rewriteJs, \"PPROXY_HOST\", fmt.Sprintf(\"127.0.0.1:%d\", reqMod.ser.conf.Port), 1)\n\n\treqMod.mu.Lock()\n\tdefer reqMod.mu.Unlock()\n\tif reqMod.ser.Debug {\n\t\tlog.Println(\"jsvm_execute:\", rewriteJs)\n\t}\n\treqMod.jsVm.Run(rewriteJs)\n\tjsFn, err := reqMod.jsVm.Get(\"pproxy_rewrite\")\n\tif err != nil {\n\t\tlog.Println(\"rewrite js init error:\", err)\n\t\treturn err\n\t}\n\n\tif strings.HasPrefix(jsStr, \"//ignore\") {\n\t\tif _, has := reqMod.jsFns[name]; has {\n\t\t\tdelete(reqMod.jsFns, name)\n\t\t}\n\t\tlog.Println(\"req_mod [\", name, \"] ignore\")\n\t} else {\n\t\treqMod.jsFns[name] = &jsFn\n\t\tlog.Println(\"req_mod [\", name, \"] register suc\")\n\t}\n\treqMod.canMod = true\n\tif save2File {\n\t\tjsPath := reqMod.getJsPath(name)\n\t\terr = fs.FilePutContents(jsPath, []byte(jsStr))\n\t\tlog.Println(\"save rewritejs \", jsPath, err)\n\t}\n\treturn err\n}\n\nfunc (reqMod *requestModifier) getJsFnByName(name string) (*otto.Value, error) {\n\tnames := []string{name, \"\"}\n\tfor _, name := range names {\n\t\tif jsFn, has := reqMod.jsFns[name]; has {\n\t\t\treturn jsFn, nil\n\t\t}\n\t}\n\treturn nil, errors.New(\"no rewrite rules\")\n}\n\nfunc (reqMod *requestModifier) rewrite(data map[string]any, name string) (map[string]any, error) {\n\treqMod.mu.Lock()\n\tdefer reqMod.mu.Unlock()\n\n\treqJsObj, _ := reqMod.jsVm.Object(`req={}`)\n\treqJsObj.Set(\"origin\", data)\n\n\tjsFn, err := reqMod.getJsFnByName(name)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer func() {\n\t\tif caught := recover(); caught != nil {\n\t\t\tlog.Println(\"fatal:requestModifer  recover:\", caught)\n\t\t}\n\t}()\n\n\tjs_ret, err_js := (*jsFn).Call(*jsFn, reqJsObj)\n\n\tif err_js != nil {\n\t\tlog.Println(\"parse js error:\", err_js)\n\t\treturn nil, err_js\n\t}\n\tif !js_ret.IsObject() {\n\t\tlog.Println(\"wrong req_rewirte return value,not object:\", js_ret)\n\t\treturn nil, fmt.Errorf(\"wrong req_rewirte return value,not object.%t\", js_ret)\n\t}\n\tobj, export_err := js_ret.Export()\n\n\tif export_err != nil {\n\t\treturn nil, export_err\n\t}\n\treqObjNew := obj.(map[string]any)\n\treturn reqObjNew, nil\n}\n"
  },
  {
    "path": "serve/req_replay.go",
    "content": "package serve\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n)\n\nconst (\n\tREPLAY_FLAG       = \"Proxy-pproxy_replay\"\n\tREPLAY_REMOTEADDR = \"Proxy-pproxy_remoteaddr\"\n\tREPLAY_USER_NAME  = \"Proxy-pproxy_user\"\n)\n\nfunc (ctx *webRequestCtx) handleReplay() {\n\tif ctx.req.Method == \"POST\" {\n\t\tctx.reqReplayPost()\n\t\treturn\n\t}\n\tdocidStr := strings.TrimSpace(ctx.req.FormValue(\"id\"))\n\tif docidStr == \"\" {\n\t\tctx.w.WriteHeader(http.StatusBadRequest)\n\t\tctx.w.Write([]byte(\"empty id param\"))\n\t\treturn\n\t}\n\tdocid, errInt := parseDocID(docidStr)\n\tif errInt != nil {\n\t\tctx.w.WriteHeader(http.StatusInternalServerError)\n\t\tfmt.Fprintf(ctx.w, \"param id[%s] error:\\n%s\", docidStr, errInt)\n\t\treturn\n\t}\n\treqDoc, _ := ctx.ser.getRequestByDocid(docid)\n\tif reqDoc == nil {\n\t\tctx.w.WriteHeader(http.StatusNotFound)\n\t\tctx.w.Write([]byte(\"request doc not found!\"))\n\t\treturn\n\t}\n\t_url := fmt.Sprintf(\"%s\", reqDoc.Data[\"url\"])\n\tu, err := url.Parse(_url)\n\tif err != nil {\n\t\tctx.w.WriteHeader(http.StatusInternalServerError)\n\t\tfmt.Fprintf(ctx.w, \"parse url[%s] error\\n%s\", _url, err)\n\t\treturn\n\t}\n\tu.RawQuery = \"\"\n\n\tctx.values[\"req\"] = reqDoc\n\tctx.values[\"action_url\"] = u.String()\n\n\tctx.render(\"replay.html\", true)\n}\n\nvar replaySkipHeaders = map[string]int{\"Content-Length\": 1}\n\nfunc (ctx *webRequestCtx) reqReplayPost() {\n\treplay := ctx.req.FormValue(\"replay\")\n\tbasic := make(map[string]string)\n\tbasic[\"action_url\"] = strings.TrimSpace(ctx.req.FormValue(\"basic_action_url\"))\n\tmethod := strings.TrimSpace(strings.ToUpper(ctx.req.FormValue(\"basic_method\")))\n\tbasic[\"method\"] = method\n\n\thost := strings.TrimSpace(ctx.req.FormValue(\"basic_host\"))\n\n\tbasicRemoteAddr := ctx.req.FormValue(\"basic_RemoteAddr\")\n\tbasicUser := ctx.req.FormValue(\"basic_user\")\n\n\theader := getFormValuesWithPrefix(ctx.req.Form, \"header_\")\n\tget := getFormValuesWithPrefix(ctx.req.Form, \"get_\")\n\tpost := getFormValuesWithPrefix(ctx.req.Form, \"post_\")\n\n\tformData := make(map[string]any)\n\tformData[\"basic\"] = basic\n\n\tformData[\"header\"] = header\n\tformData[\"get\"] = get\n\tformData[\"post\"] = post\n\n\tctx.values[\"form\"] = formData\n\tif replay == \"direct\" {\n\t\tctx.render(\"replay_direct.html\", true)\n\t\treturn\n\t}\n\treqBd := \"\"\n\t_url := basic[\"action_url\"]\n\n\tif len(get) > 0 {\n\t\tformValues := make(url.Values)\n\t\tfor k, v := range get {\n\t\t\tfor _, _v := range v {\n\t\t\t\tformValues.Add(k, _v)\n\t\t\t}\n\t\t}\n\t\tif strings.Contains(_url, \"?\") {\n\t\t\t_url += \"&\"\n\t\t} else {\n\t\t\t_url += \"?\"\n\t\t}\n\t\t_url += formValues.Encode()\n\t}\n\n\tif len(post) > 0 {\n\t\tformValues := make(url.Values)\n\t\tfor k, v := range post {\n\t\t\tfor _, _v := range v {\n\t\t\t\tformValues.Add(k, _v)\n\t\t\t}\n\t\t}\n\t\treqBd = formValues.Encode()\n\t}\n\n\treplayReq, err := http.NewRequest(method, _url, strings.NewReader(reqBd))\n\tif err != nil {\n\t\tctx.w.Write([]byte(\"build request failed\\n\" + err.Error()))\n\t\treturn\n\t}\n\tif host != \"\" {\n\t\treplayReq.Host = host\n\t}\n\treplayReq.Header.Set(REPLAY_FLAG, \"replay\")\n\n\treplayReq.Header.Set(REPLAY_REMOTEADDR, basicRemoteAddr)\n\treplayReq.Header.Set(REPLAY_USER_NAME, basicUser)\n\n\tfor k, v := range header {\n\t\tif _, has := replaySkipHeaders[k]; has {\n\t\t\tcontinue\n\t\t}\n\t\treplayReq.Header.Set(k, strings.Join(v, \";\"))\n\t}\n\tctx.ser.ServeHTTPProxy(ctx.w, replayReq)\n}\n"
  },
  {
    "path": "serve/req_rewrite.go",
    "content": "package serve\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc (ser *ProxyServe) reqRewriteByjs(reqCtx *requestCtx) int {\n\tmodifer := ser.reqMod\n\tif !modifer.CanMod() {\n\t\treturn 304\n\t}\n\treq := reqCtx.Req\n\tschema := req.URL.Scheme\n\toriginURL := req.URL.String()\n\toriginGetQuery := req.URL.Query()\n\t// /================================================================\n\theaderKv := make(map[string]string)\n\theaderKv[\"method\"] = req.Method\n\theaderKv[\"schema\"] = schema\n\theaderKv[\"path\"] = req.URL.Path\n\n\t_host, portInt, _ := getHostPortFromReq(req)\n\n\theaderKv[\"host\"] = _host\n\theaderKv[\"port\"] = strconv.Itoa(portInt)\n\n\tusername := \"\"\n\tpsw := \"\"\n\tif req.URL.User != nil {\n\t\tusername = req.URL.User.Username()\n\t\tpsw, _ = req.URL.User.Password()\n\t}\n\theaderKv[\"username\"] = username\n\n\theaderKv[\"proxy_user\"] = reqCtx.User.Name\n\n\theaderKv[\"password\"] = psw\n\n\t// ===================================================================\n\trewriteData := make(map[string]any)\n\trewriteData[\"header\"] = headerKv\n\trewriteData[\"get\"] = originGetQuery\n\trewriteData[\"post\"] = *reqCtx.FormPost\n\n\t_buf := forgetRead(&reqCtx.Req.Body)\n\tvar rawBody string\n\t//  暂时只考虑gip的，其他的压缩就不支持了\n\tif req.Header.Get(contentEncoding) == \"gzip\" {\n\t\trawBody = gzipDocode(_buf)\n\t} else {\n\t\trawBody = _buf.String()\n\t}\n\trewriteData[\"body\"] = rawBody\n\n\treqObjNew, rErr := modifer.rewrite(rewriteData, reqCtx.User.Name)\n\tif rErr != nil {\n\t\tlog.Println(\"rewrite failed:\", rErr)\n\t}\n\n\theaderKvNew := make(map[string]string)\n\tisHeaderChange := false\n\n\tskipHeader := false\n\tvar err error\n\n\turlStrNew := getMapValStr(reqObjNew, \"url\")\n\n\tif urlStrNew != \"\" {\n\t\treq.URL, err = url.Parse(urlStrNew)\n\t\tif err != nil || req.URL.Scheme != \"http\" {\n\t\t\tlog.Println(\"new url wrong!url is:\", urlStrNew, err)\n\t\t\treturn 500\n\t\t}\n\t\treq.Host = req.URL.Host\n\t\tskipHeader = true\n\t}\n\n\tif !skipHeader {\n\t\tfor k, v := range headerKv {\n\t\t\t_newVal := getMapValStr(reqObjNew, k)\n\t\t\theaderKvNew[k] = _newVal\n\t\t\tif _newVal != v {\n\t\t\t\tisHeaderChange = true\n\t\t\t}\n\t\t}\n\t}\n\t// -------------------------------------------------------\n\tvar getNew url.Values\n\n\tisGetChange := false\n\n\tif _get, has := reqObjNew[\"get\"]; has {\n\t\tgetNew = _reqMapToURLValue(_get)\n\t\tisGetChange = checkURLValuesChange(originGetQuery, getNew)\n\t}\n\t// -------------------------------------------------------\n\tvar postNew url.Values\n\tisPostChange := false\n\n\tif schema == \"http\" {\n\t\tif _post, has := reqObjNew[\"post\"]; has {\n\t\t\tpostNew = _reqMapToURLValue(_post)\n\t\t\tisPostChange = checkURLValuesChange(*reqCtx.FormPost, postNew)\n\t\t}\n\t}\n\tisBodyChange := false\n\tbodyNew := \"\"\n\tif _bodyNew, has := reqObjNew[\"body\"]; has {\n\t\tbodyNew = _bodyNew.(string)\n\t\tisBodyChange = rawBody != bodyNew\n\t}\n\n\thostAddr := getMapValStr(reqObjNew, \"hostAddr\")\n\tisHostAddrChange := hostAddr != \"\"\n\n\tif ser.Debug {\n\t\tfmt.Println(\"rewriteChange:\", \"is_get_change:\", isGetChange, \"new_get:\", getNew,\n\t\t\t\"isPostChange:\", isPostChange, \"new_post:\", postNew,\n\t\t\t\"isHostAddrChange:\", isHostAddrChange, \"newHostAddr:\", hostAddr,\n\t\t\t\"isBodyChange:\", isBodyChange,\n\t\t)\n\t}\n\n\t// /===============================================================================\n\tif !isHeaderChange && !isGetChange && !isPostChange && !isHostAddrChange && !isBodyChange {\n\t\treturn 304\n\t}\n\t// /===============================================================================\n\n\tvar urlBase string\n\n\tif isHeaderChange {\n\t\t// \t\tschema := headerKvNew[\"schema\"]\n\t\turlBase = schema + \"://\"\n\n\t\tif headerKvNew[\"username\"] != \"\" {\n\t\t\turlBase += fmt.Sprintf(\"%s:%s@\", headerKvNew[\"username\"], headerKvNew[\"password\"])\n\t\t}\n\t\turlBase += headerKvNew[\"host\"]\n\t\tif headerKvNew[\"port\"] != \"\" && headerKvNew[\"port\"] != \"80\" {\n\t\t\turlBase += \":\" + headerKvNew[\"port\"]\n\t\t}\n\t\turlBase += headerKvNew[\"path\"]\n\t} else {\n\t\tif req.URL.RawQuery == \"\" {\n\t\t\turlBase = originURL\n\t\t} else {\n\t\t\turlBase = originURL[:len(originURL)-len(req.URL.RawQuery)-1]\n\t\t}\n\t}\n\n\tif isGetChange {\n\t\turlBase += \"?\" + getNew.Encode()\n\t} else {\n\t\turlBase += \"?\" + req.URL.RawQuery\n\t}\n\n\tif isHeaderChange || isGetChange {\n\t\tvar urlErr error\n\t\treq.URL, urlErr = url.Parse(urlBase)\n\t\tif ser.Debug {\n\t\t\tlog.Println(\"DEBUG req_rewrite,url_new:\", urlBase, \"req_new:\", req.URL)\n\t\t}\n\t\tif urlErr != nil {\n\t\t\treturn 502\n\t\t}\n\n\t\treq.Host = req.URL.Host\n\t}\n\n\t// ////////////////////////////////////////////////////////////////////////////\n\n\tif isPostChange || isBodyChange {\n\t\tbuf := bytes.NewBuffer([]byte{})\n\t\tvar bodyData string\n\t\tif isPostChange {\n\t\t\tbodyData = postNew.Encode()\n\t\t} else if isBodyChange {\n\t\t\tbodyData = bodyNew\n\t\t}\n\t\treq.Header.Del(\"Content-Length\")\n\t\tif req.Header.Get(contentEncoding) == \"gzip\" {\n\t\t\ttmp := gzipEncode([]byte(bodyData)).Bytes()\n\t\t\tbuf.Write(tmp)\n\t\t} else {\n\t\t\tbuf.WriteString(bodyData)\n\t\t}\n\t\treq.ContentLength = int64(buf.Len())\n\t\treq.Body = io.NopCloser(buf).(io.ReadCloser)\n\t}\n\n\t// //////////////////////////////////////////////////////////////////////////\n\n\tif isHostAddrChange {\n\t\treq.URL.Host = hostAddr\n\t\tif ser.Debug {\n\t\t\tlog.Println(\"rewrite host addr:\", req.URL.Host, \"==>\", hostAddr)\n\t\t}\n\t}\n\treturn 200\n}\n\nfunc (ser *ProxyServe) reqRewrite(reqCtx *requestCtx) int {\n\tif !ser.conf.ModifyRequest {\n\t\treturn 304\n\t}\n\tif reqCtx.Req.Method == \"CONNECT\" {\n\t\treturn 304\n\t}\n\toriginHost := reqCtx.Req.Host + \"#\" + reqCtx.Req.URL.Host\n\tstatusCode1 := ser.reqRewriteByjs(reqCtx)\n\tnewHost := reqCtx.Req.Host + \"#\" + reqCtx.Req.URL.Host\n\n\tif ser.Debug {\n\t\tlog.Println(\"rewrte_debug:\\n\", \"originHost:\", originHost, \"\\nnewHost:\", newHost, \"\\n\")\n\t}\n\n\tstatusCode2 := 304\n\tif originHost == newHost {\n\t\tstatusCode2 = ser.reqRewriteByHosts(reqCtx.Req)\n\t}\n\tif statusCode1 == 200 || statusCode2 == 200 {\n\t\treturn 200\n\t}\n\tif statusCode1 >= 500 || statusCode2 >= 500 {\n\t\treturn 502\n\t}\n\treturn 304\n}\n\nfunc (ser *ProxyServe) reqRewriteByHosts(req *http.Request) int {\n\tif ser.hosts == nil {\n\t\treturn 304\n\t}\n\tif host, has := ser.hosts[req.URL.Host]; has {\n\t\tlog.Println(\"rewrite host:\", req.URL.Host, \"==>\", host)\n\t\treq.URL.Host = host\n\t\treturn 200\n\t}\n\thostInfo := strings.Split(req.URL.Host, \":\")\n\tif len(hostInfo) == 1 {\n\t\tif req.URL.Scheme == \"http\" {\n\t\t\thostInfo = append(hostInfo, \"80\")\n\t\t}\n\t}\n\treqHost := strings.Join(hostInfo, \":\")\n\tif host, has := ser.hosts[reqHost]; has {\n\t\tlog.Println(\"rewrite host:\", req.Host, \"==>\", host)\n\t\treq.URL.Host = host\n\t\treturn 200\n\t}\n\n\tif host, has := ser.hosts[hostInfo[0]]; has {\n\t\tlog.Println(\"rewrite host:\", req.Host, \"==>\", host)\n\t\treq.URL.Host = host\n\t\tif !strings.Contains(host, \":\") {\n\t\t\treq.URL.Host += \":\" + hostInfo[1]\n\t\t}\n\t\treturn 200\n\t}\n\treturn 304\n}\n\nfunc _reqMapToURLValue(values any) url.Values {\n\tuValues := make(url.Values)\n\tif values == nil {\n\t\treturn uValues\n\t}\n\tvs := values.(map[string]any)\n\n\tfor k, arr := range vs {\n\t\tswitch value := arr.(type) {\n\t\tcase []any:\n\t\t\tfor _, v := range value {\n\t\t\t\tuValues.Add(k, fmt.Sprintf(\"%v\", v))\n\t\t\t}\n\t\tcase any:\n\t\t\tuValues.Set(k, fmt.Sprintf(\"%v\", value))\n\t\tdefault:\n\t\t\tlog.Println(\"unkonw type:\", value)\n\t\t}\n\t}\n\treturn uValues\n}\n"
  },
  {
    "path": "serve/serve.go",
    "content": "package serve\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/hidu/goutils/fs\"\n\t\"github.com/hidu/goutils/time_util\"\n)\n\ntype ProxyServe struct {\n\tmydb  *kvStore\n\tproxy *HttpProxy\n\n\twsSer *wsServer\n\n\tstartTime time.Time\n\n\tMaxResSaveLength int64\n\n\tmu sync.RWMutex\n\n\tDebug bool\n\n\tconf      *Config\n\tconfigDir string\n\thosts     configHosts\n\n\tUsers        map[string]*User\n\tProxyClients map[string]*clientSession\n\treqNum       int64\n\n\treqMod *requestModifier\n}\n\ntype KvType map[string]any\n\nfunc (ser *ProxyServe) ServeHTTP(w http.ResponseWriter, req *http.Request) {\n\tatomic.AddInt64(&ser.reqNum, 1)\n\n\t// \treqDump, _ := httputil.DumpRequest(req, true)\n\t//    fmt.Println(\"req dump:\\n\",string(reqDump))\n\n\tctx := NewRequestCtx(ser, w, req)\n\tif ctx.Host == \"p.info\" || ctx.Host == \"pproxy.info\" {\n\t\tser.handleUserInfo(w, req)\n\t\treturn\n\t}\n\n\tif ctx.Host == \"pproxy.man\" || ctx.Host == \"pproxy.com\" || ctx.IsLocalRequest() {\n\t\tser.handleLocalReq(w, req)\n\t} else {\n\t\tif ser.Debug {\n\t\t\treqDumpDebug, _ := httputil.DumpRequest(req, req.Method == \"GET\")\n\t\t\tlog.Println(\"DEBUG req BEFORE:\\nurl_full:\", req.URL.String(), \"\\nschema:\", req.URL.Scheme, \"\\n\", string(reqDumpDebug), \"\\n\\n\")\n\t\t}\n\t\tif !ser.checkHTTPAuth(ctx) {\n\t\t\tctx.SetLog(\"msg\", \"login required\")\n\t\t\tctx.Rw.Header().Set(\"Proxy-Authenticate\", \"Basic realm=auth required\")\n\t\t\tctx.Rw.WriteHeader(http.StatusProxyAuthRequired)\n\t\t\tctx.Rw.Write([]byte(\"auth required\"))\n\t\t\treturn\n\t\t}\n\t\tctx.RoundTrip()\n\t}\n}\n\n// for replay\nfunc (ser *ProxyServe) ServeHTTPProxy(w http.ResponseWriter, req *http.Request) {\n\tatomic.AddInt64(&ser.reqNum, 1)\n\tctx := NewRequestCtx(ser, w, req)\n\tctx.RoundTrip()\n}\n\nfunc (ser *ProxyServe) Start() {\n\taddr := fmt.Sprintf(\"%s:%d\", \"\", ser.conf.Port)\n\tfmt.Println(\"proxy listen at \", addr)\n\tdefer log.Println(\"pproxy exit\")\n\n\tser.wsInit()\n\n\twg := new(sync.WaitGroup)\n\twg.Add(1)\n\tgo func() {\n\t\terr := http.ListenAndServe(addr, ser)\n\t\tlog.Println(err)\n\t\tfmt.Println(err)\n\t\twg.Done()\n\t}()\n\n\twg.Add(1)\n\tgo func() {\n\t\tser.startAdmin()\n\t\twg.Done()\n\t}()\n\n\twg.Wait()\n}\n\nfunc (ser *ProxyServe) startAdmin() {\n\tif ser.conf.Port == ser.conf.AdminPort {\n\t\treturn\n\t}\n\taddr := fmt.Sprintf(\":%d\", ser.conf.AdminPort)\n\tfmt.Println(\"admin http service listen at \", addr)\n\thttpSer := http.NewServeMux()\n\thttpSer.HandleFunc(\"/\", func(w http.ResponseWriter, req *http.Request) {\n\t\tser.handleLocalReq(w, req)\n\t})\n\thttp.ListenAndServe(addr, httpSer)\n}\n\nfunc (ser *ProxyServe) getResponseByDocid(docid int) (resData *StoreType, err error) {\n\ttb := ser.mydb.GetkvStoreTable(KV_TABLE_RES)\n\treturn tb.Get(IntToBytes(docid))\n}\n\nfunc (ser *ProxyServe) getRequestByDocid(docid int) (reqData *StoreType, err error) {\n\ttb := ser.mydb.GetkvStoreTable(KV_TABLE_REQ)\n\treturn tb.Get(IntToBytes(docid))\n}\n\nfunc (ser *ProxyServe) getHostsFilePath() string {\n\treturn fmt.Sprintf(\"%s/hosts_%d\", ser.configDir, ser.conf.Port)\n}\n\nfunc (ser *ProxyServe) loadHosts() {\n\tser.mu.Lock()\n\tdefer ser.mu.Unlock()\n\thostsPath := ser.getHostsFilePath()\n\tlog.Println(\"load hosts:\", hostsPath)\n\tser.hosts, _ = loadHosts(hostsPath)\n}\n\nfunc NewProxyServe(confPath string, port int) (*ProxyServe, error) {\n\tconf, err := LoadConfig(confPath)\n\tif err != nil {\n\t\tlog.Println(\"load config faield\", err)\n\t\treturn nil, err\n\t}\n\tif port > 0 && port < 65535 {\n\t\tconf.Port = port\n\t}\n\n\tabsPath, err := filepath.Abs(confPath)\n\tif err != nil {\n\t\tlog.Println(\"get config path failed\", confPath)\n\t\treturn nil, err\n\t}\n\tGetVersion()\n\tos.Chdir(filepath.Dir(absPath))\n\tsetupLog(conf.DataDir, conf.Port)\n\n\tproxy := new(ProxyServe)\n\tproxy.configDir = filepath.Dir(absPath)\n\tproxy.Users, _ = loadUsers(proxy.configDir + \"/users\")\n\n\tconf.FileDir, _ = filepath.Abs(conf.FileDir)\n\n\tproxy.conf = conf\n\n\tproxy.reqMod = NewRequestModifier(proxy)\n\terr = proxy.reqMod.loadAllJs()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tproxy.loadHosts()\n\n\tdbPath := fmt.Sprintf(\"%s/%d.db\", conf.DataDir, conf.Port)\n\n\t// \tproxy.mydb = NewTieDb(fmt.Sprintf(\"%s/%d/\", conf.DataDir, conf.Port), conf.DataStoreDay)\n\tproxy.mydb, err = newKvStore(dbPath)\n\tif err != nil {\n\t\tlog.Fatalln(\"init db failed\", err)\n\t}\n\n\tproxy.startTime = time.Now()\n\tproxy.MaxResSaveLength = 2 * 1024 * 1024\n\n\trand.Seed(time.Now().UnixNano())\n\n\tproxy.ProxyClients = make(map[string]*clientSession)\n\tproxy.proxy = NewHttpProxy(proxy)\n\n\ttime_util.SetInterval(func() {\n\t\tproxy.cleanExpiredSession()\n\t}, 60)\n\tproxy.mydb.StartGcTimer(60, int64(conf.DataStoreDay*86400))\n\treturn proxy, nil\n}\n\nfunc setupLog(dataDir string, port int) {\n\tlogPath := fmt.Sprintf(\"%s/%d.log\", dataDir, port)\n\n\tlogFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)\n\tif err != nil {\n\t\tlog.Println(\"create log file failed [\", logPath, \"]\", err)\n\t\tos.Exit(2)\n\t}\n\tlog.SetOutput(logFile)\n\n\ttime_util.SetInterval(func() {\n\t\tif !fs.FileExists(logPath) {\n\t\t\tlogFile.Close()\n\t\t\tlogFile, _ = os.OpenFile(logPath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)\n\t\t\tlog.SetOutput(logFile)\n\t\t}\n\t}, 30)\n}\n"
  },
  {
    "path": "serve/sessions.go",
    "content": "package serve\n\nimport (\n\t\"log\"\n\t\"time\"\n)\n\ntype clientSession struct {\n\tIp               string\n\tPort             string\n\tRequestNum       int\n\tFirstRequestTime time.Time\n\tLastRequestTime  time.Time\n\tUser             *User\n}\n\nfunc (ser *ProxyServe) regirestReq(reqCtx *requestCtx) {\n\tip := reqCtx.GetIp()\n\tnow := time.Now()\n\tser.mu.Lock()\n\tdefer ser.mu.Unlock()\n\tvar session *clientSession\n\tclient, has := ser.ProxyClients[ip]\n\tif has {\n\t\tsession = client\n\t} else {\n\t\tsession = &clientSession{\n\t\t\tIp:               ip,\n\t\t\tRequestNum:       0,\n\t\t\tFirstRequestTime: now,\n\t\t\tLastRequestTime:  now,\n\t\t}\n\t}\n\tif reqCtx.User.Name == \"\" && session.User != nil {\n\t\treqCtx.User = session.User\n\t} else if reqCtx.User.Name != \"\" {\n\t\tsession.User = reqCtx.User\n\t}\n\n\tsession.LastRequestTime = now\n\tsession.RequestNum++\n\tif ser.Debug {\n\t\tlog.Println(\"session_debug:\", session)\n\t}\n\tser.ProxyClients[ip] = session\n\n\treqCtx.ClientSession = session\n\n\tif !has {\n\t\tser.wsSer.broadProxyClientNum()\n\t}\n}\n\nfunc (ser *ProxyServe) cleanExpiredSession() {\n\tser.mu.Lock()\n\tdefer ser.mu.Unlock()\n\tnow := time.Now()\n\tdeleteIps := []string{}\n\tfor ip, session := range ser.ProxyClients {\n\t\tt := now.Sub(session.LastRequestTime)\n\t\tif t.Minutes() > 10 {\n\t\t\tdeleteIps = append(deleteIps, ip)\n\t\t}\n\t}\n\tfor _, ip := range deleteIps {\n\t\tdelete(ser.ProxyClients, ip)\n\t\tlog.Println(\"session expired:ip=\", ip)\n\t}\n\tser.wsSer.broadProxyClientNum()\n}\n"
  },
  {
    "path": "serve/util.go",
    "content": "package serve\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t// \"encoding/base64\"\n\t\"encoding/binary\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\n\t// \"gopkg.in/vmihailenco/msgpack.v2\"\n)\n\n// Int64ToBytes int64转换为byte\nfunc Int64ToBytes(i int64) []byte {\n\tvar buf = make([]byte, 8)\n\tbinary.BigEndian.PutUint64(buf, uint64(i))\n\treturn buf\n}\n\n// IntToBytes int转换为byte\nfunc IntToBytes(i int) []byte {\n\tvar buf = make([]byte, 8)\n\tbinary.BigEndian.PutUint64(buf, uint64(i))\n\treturn buf\n}\n\n// IsLocalIP 判断一个host是否本地ip\nfunc IsLocalIP(host string) bool {\n\tips, _ := net.LookupIP(host)\n\tfor _, ip := range ips {\n\t\tif ip.IsLoopback() {\n\t\t\treturn true\n\t\t}\n\t}\n\tif addrs, err := net.InterfaceAddrs(); err == nil {\n\t\tfor _, addr := range addrs {\n\t\t\t_, ipG, err := net.ParseCIDR(addr.String())\n\t\t\tif err == nil {\n\t\t\t\tfor _, ip := range ips {\n\t\t\t\t\tif ipG.Contains(ip) {\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\t}\n\treturn false\n}\n\nfunc forgetRead(reader *io.ReadCloser) *bytes.Buffer {\n\tbuf := bytes.NewBuffer([]byte{})\n\tio.Copy(buf, *reader)\n\t*reader = io.NopCloser(buf).(io.ReadCloser)\n\treturn bytes.NewBuffer(buf.Bytes())\n}\n\nfunc dataEncode(data any) []byte {\n\tbf, err := json.Marshal(data)\n\tif err != nil {\n\t\tlog.Println(\"data_encode_err\", err)\n\t\treturn bf\n\t}\n\treturn bf\n}\n\nfunc dataDecode(dataInput []byte, out any) error {\n\tif len(dataInput) == 0 {\n\t\treturn errors.New(\"empty dataInput\")\n\t}\n\terr := json.Unmarshal(dataInput, &out)\n\tif err != nil {\n\t\tlog.Println(\"json_decode_err:\", err, \"dataInput:\", string(dataInput))\n\t\treturn err\n\t}\n\treturn err\n}\n\nfunc getMapValStr(m map[string]any, k string) string {\n\tif val, has := m[k]; has {\n\t\treturn fmt.Sprintf(\"%s\", val)\n\t}\n\treturn \"\"\n}\n\nfunc gzipDocode(buf *bytes.Buffer) string {\n\tif buf.Len() < 1 {\n\t\treturn \"\"\n\t}\n\tgr, err := gzip.NewReader(buf)\n\tdefer gr.Close()\n\tif err == nil {\n\t\tbdBt, _ := io.ReadAll(gr)\n\t\treturn string(bdBt)\n\t}\n\tlog.Println(\"unzip body failed\", err)\n\treturn \"\"\n}\n\nfunc gzipEncode(data []byte) *bytes.Buffer {\n\tbuf := bytes.NewBuffer([]byte{})\n\tgw := gzip.NewWriter(buf)\n\tdefer gw.Close()\n\tgw.Write(data)\n\treturn buf\n}\n\nfunc parseURLInputAsSlice(input string) []string {\n\tarr := strings.Split(input, \"|\")\n\tvar result []string\n\tfor _, val := range arr {\n\t\tval = strings.TrimSpace(val)\n\t\tif val != \"\" {\n\t\t\tresult = append(result, val)\n\t\t}\n\t}\n\treturn result\n}\n\nfunc getFormValuesWithPrefix(values url.Values, prefix string) map[string][]string {\n\tresult := make(map[string][]string)\n\tfor k, v := range values {\n\t\tif strings.HasPrefix(k, prefix) {\n\t\t\tk1 := strings.TrimPrefix(k, prefix)\n\t\t\tresult[k1] = v\n\t\t}\n\t}\n\treturn result\n}\n\nfunc getTextAreaHeightByString(mystr string, minHeight int) int {\n\theight := (len(strings.Split(mystr, \"\\n\")) + 1) * 25\n\tif height < minHeight {\n\t\theight = minHeight\n\t}\n\treturn height\n}\n\nfunc getHostPortFromReq(req *http.Request) (host string, port int, err error) {\n\thost, port, err = parseHostPort(req.Host)\n\tif err == nil && port == 0 {\n\t\tswitch req.URL.Scheme {\n\t\tcase \"http\":\n\t\t\tport = 80\n\t\t\tbreak\n\t\tcase \"https\":\n\t\t\tport = 443\n\t\t\tbreak\n\t\tdefault:\n\t\t\tbreak\n\t\t}\n\t}\n\treturn\n}\n\nfunc parseHostPort(hostPortstr string) (host string, port int, err error) {\n\tvar portStr string\n\tif !strings.Contains(hostPortstr, \":\") {\n\t\thostPortstr += \":0\"\n\t}\n\thost, portStr, err = net.SplitHostPort(hostPortstr)\n\tif err != nil {\n\t\treturn\n\t}\n\tport, err = strconv.Atoi(portStr)\n\tif err != nil {\n\t\treturn\n\t}\n\treturn\n}\n\nfunc checkURLValuesChange(first url.Values, second url.Values) (change bool) {\n\tfor k, v := range first {\n\t\tsecV, has := second[k]\n\t\tif !has {\n\t\t\treturn true\n\t\t}\n\t\tif len(v) != len(secV) || fmt.Sprintf(\"%v\", v) != fmt.Sprintf(\"%v\", secV) {\n\t\t\treturn true\n\t\t}\n\t}\n\tfor k, v := range second {\n\t\tfirstV, has := first[k]\n\t\tif !has {\n\t\t\treturn true\n\t\t}\n\t\tif len(v) != len(firstV) || fmt.Sprintf(\"%v\", v) != fmt.Sprintf(\"%v\", firstV) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc parseDocID(strid string) (docid int, err error) {\n\tdocid64, parseErr := strconv.ParseUint(strid, 10, 64)\n\tif parseErr == nil {\n\t\treturn int(docid64), nil\n\t}\n\treturn 0, parseErr\n}\n\nfunc removeHeader(req *http.Request) {\n\tfor k := range req.Header {\n\t\tif len(k) > 5 && k[:6] == \"Proxy-\" {\n\t\t\treq.Header.Del(k)\n\t\t}\n\t}\n}\n\nfunc getPostData(req *http.Request) (post *url.Values) {\n\tpost = new(url.Values)\n\tif strings.Contains(req.Header.Get(\"Content-Type\"), \"x-www-form-urlencoded\") {\n\t\tbuf := forgetRead(&req.Body)\n\t\tvar bodyStr string\n\t\tif req.Header.Get(contentEncoding) == \"gzip\" {\n\t\t\tbodyStr = gzipDocode(buf)\n\t\t} else {\n\t\t\tbodyStr = buf.String()\n\t\t}\n\t\tvar err error\n\t\t*post, err = url.ParseQuery(bodyStr)\n\t\tif err != nil {\n\t\t\tlog.Println(\"parse post err\", err, \"url=\", req.URL.String())\n\t\t}\n\t}\n\treturn post\n}\n\nfunc headerEncode(data []byte) []byte {\n\tt := bytes.Replace(data, []byte(\"\\r\"), []byte(\"\\\\r\"), -1)\n\tt = bytes.Replace(t, []byte(\"\\n\"), []byte(\"\\\\n\"), -1)\n\treturn t\n}\n"
  },
  {
    "path": "serve/web.go",
    "content": "package serve\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"html\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"github.com/hidu/goutils/fs\"\n\t\"github.com/hidu/goutils/html_util\"\n\t\"github.com/hidu/goutils/object\"\n)\n\ntype webRequestCtx struct {\n\tvalues  map[string]any\n\tuser    *User\n\tisLogin bool\n\tisAdmin bool\n\treq     *http.Request\n\tw       http.ResponseWriter\n\tser     *ProxyServe\n}\n\nvar cookieName = \"pproxy\"\n\nfunc (ser *ProxyServe) handleLocalReq(w http.ResponseWriter, req *http.Request) {\n\taccessLogStr := \"web_access \" + req.Method + \" \" + req.URL.String() + \" \" + req.RemoteAddr + \" refer:\" + req.Referer()\n\tdefer (func() {\n\t\tlog.Println(accessLogStr)\n\t})()\n\n\tif strings.HasPrefix(req.URL.Path, \"/socket.io/\") {\n\t\tser.wsSer.server.ServeHTTP(w, req)\n\t\treturn\n\t}\n\n\tif strings.HasPrefix(req.URL.Path, \"/f/\") {\n\t\treq.URL.Path = req.URL.Path[3:]\n\t\thttp.FileServer(http.Dir(ser.conf.FileDir)).ServeHTTP(w, req)\n\t\treturn\n\t}\n\n\tif strings.HasPrefix(req.URL.Path, \"/res/\") {\n\t\tAssest.HTTPHandler(\"/\").ServeHTTP(w, req)\n\t\treturn\n\t}\n\n\tvalues := make(map[string]any)\n\tvalues[\"title\"] = ser.conf.Title\n\tvalues[\"subTitle\"] = \"\"\n\tvalues[\"version\"] = PproxyVersion\n\tvalues[\"notice\"] = ser.conf.Notice\n\tvalues[\"port\"] = strconv.Itoa(ser.conf.Port)\n\tvalues[\"userOnlineTotal\"] = len(ser.ProxyClients)\n\t_host, _, _ := getHostPortFromReq(req)\n\tvalues[\"pproxy_host\"] = _host\n\tvalues[\"pproxy_port\"] = ser.conf.Port\n\n\tctx := &webRequestCtx{\n\t\tvalues: values,\n\t\tw:      w,\n\t\treq:    req,\n\t\tser:    ser,\n\t}\n\tctx.checkLogin()\n\n\tfuncMap := make(map[string]func())\n\tfuncMap[\"/\"] = ctx.handle_index\n\tfuncMap[\"/about\"] = ctx.handle_about\n\tfuncMap[\"/config\"] = ctx.handleConfig\n\tfuncMap[\"/useage\"] = ctx.handle_useage\n\tfuncMap[\"/replay\"] = ctx.handleReplay\n\tfuncMap[\"/login\"] = ctx.handle_login\n\tfuncMap[\"/logout\"] = ctx.handle_logout\n\tfuncMap[\"/response\"] = ctx.handle_response\n\tfuncMap[\"/file\"] = ctx.handle_file\n\n\tif fn, has := funcMap[req.URL.Path]; has {\n\t\tif len(req.URL.Path) > 1 {\n\t\t\tctx.values[\"subTitle\"] = req.URL.Path[1:] + \" |\"\n\t\t}\n\t\tfn()\n\t} else {\n\t\tctx.showError(\"404\")\n\t}\n}\n\nfunc (ser *ProxyServe) web_checkLogin(req *http.Request) (user *User, isLogin bool) {\n\tif req == nil {\n\t\treturn\n\t}\n\tcookie, err := req.Cookie(cookieName)\n\tif err != nil {\n\t\treturn\n\t}\n\tinfo := strings.SplitN(cookie.Value, \":\", 2)\n\tif len(info) != 2 {\n\t\treturn\n\t}\n\tif user, has := ser.Users[info[0]]; has {\n\t\tif user.PswMd5 == info[1] {\n\t\t\treturn user, true\n\t\t}\n\t}\n\treturn\n}\n\nfunc (ctx *webRequestCtx) checkLogin() {\n\tuser, isLogin := ctx.ser.web_checkLogin(ctx.req)\n\tif isLogin {\n\t\tctx.user = user\n\t\tctx.isLogin = true\n\t\tctx.isAdmin = user.IsAdmin\n\t}\n\tctx.values[\"isLogin\"] = ctx.isLogin\n\tctx.values[\"user\"] = ctx.user\n\tctx.values[\"isAdmin\"] = ctx.isAdmin\n}\n\nfunc (ctx *webRequestCtx) handle_index() {\n\tctx.render(\"network.html\", true)\n}\n\nfunc (ctx *webRequestCtx) handle_useage() {\n\tctx.render(\"useage.html\", true)\n}\n\nfunc (ctx *webRequestCtx) getRewriteJsInfo(name string, title string) map[string]any {\n\tinfo := make(map[string]any)\n\tjsStr, _ := ctx.ser.reqMod.getJsContent(name)\n\n\tre := regexp.MustCompile(`use_file\\([\"'](.+)[\"']\\)`)\n\tmatches := re.FindAllStringSubmatch(jsStr, -1)\n\n\t// \tfmt.Println(matches)\n\n\tvar useFile []map[string]any\n\ttmpNames := make(map[string]int)\n\n\tfor _, subMatch := range matches {\n\t\tif len(subMatch) != 2 {\n\t\t\tcontinue\n\t\t}\n\t\tuse := make(map[string]any)\n\t\tfileName := strings.TrimSpace(subMatch[1])\n\t\tuse[\"name\"] = subMatch[0]\n\t\tuse[\"file\"] = fileName\n\n\t\tif _, has := tmpNames[fileName]; has {\n\t\t\tcontinue\n\t\t}\n\t\ttmpNames[fileName] = 1\n\n\t\tisURL := strings.HasPrefix(fileName, \"http://\")\n\t\tuse[\"isUrl\"] = isURL\n\t\tif isURL {\n\t\t\tuse[\"url\"] = subMatch[1]\n\t\t} else {\n\t\t\twebFile, err := newWebFileInfo(ctx.ser.conf.FileDir, fileName)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tuse[\"url\"] = webFile.link()\n\t\t\tdefer webFile.Close()\n\t\t}\n\t\tuseFile = append(useFile, use)\n\t}\n\n\tinfo[\"name\"] = name\n\tinfo[\"use_file\"] = useFile\n\tinfo[\"title\"] = title\n\tinfo[\"rewriteJs\"] = html.EscapeString(jsStr)\n\tinfo[\"jsHeight\"] = getTextAreaHeightByString(jsStr, 100)\n\treturn info\n}\n\nfunc (ctx *webRequestCtx) handleConfig() {\n\tif ctx.req.Method == \"GET\" {\n\t\tjsDataArr := make([]any, 0, 2)\n\t\tjsDataArr = append(jsDataArr, ctx.getRewriteJsInfo(\"\", \"global config\"))\n\n\t\tif ctx.isLogin {\n\t\t\tjsDataArr = append(jsDataArr, ctx.getRewriteJsInfo(ctx.user.Name, ctx.user.Name+\"'s config\"))\n\t\t}\n\n\t\tctx.values[\"jss\"] = jsDataArr\n\n\t\thostsByte, _ := fs.FileGetContents(ctx.ser.getHostsFilePath())\n\t\tctx.values[\"hosts\"] = html.EscapeString(string(hostsByte))\n\t\tctx.values[\"hostsHeight\"] = getTextAreaHeightByString(\"\", 100)\n\n\t\tctx.render(\"config.html\", true)\n\t} else if ctx.req.Method == \"POST\" {\n\t\tif !ctx.isLogin {\n\t\t\tctx.jsAlert(\"login first\")\n\t\t\treturn\n\t\t}\n\t\tdo := ctx.req.PostFormValue(\"type\")\n\t\tvar err error\n\t\tif do == \"js\" {\n\t\t\tname := strings.TrimSpace(ctx.req.PostFormValue(\"name\"))\n\t\t\tif !ctx.isAdmin && name != ctx.user.Name {\n\t\t\t\tctx.jsAlert(\"you are not admin\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\tjsStr := strings.TrimSpace(ctx.req.PostFormValue(\"js\"))\n\t\t\terr = ctx.ser.reqMod.parseJs(jsStr, name, true)\n\t\t} else if do == \"hosts\" {\n\t\t\tif !ctx.isAdmin {\n\t\t\t\tctx.jsAlert(\"you are not admin\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\thosts := strings.TrimSpace(ctx.req.PostFormValue(\"hosts\"))\n\t\t\tlog.Println(\"hosts_update\", hosts)\n\t\t\terr = fs.FilePutContents(ctx.ser.getHostsFilePath(), []byte(hosts))\n\t\t\tctx.ser.loadHosts()\n\t\t}\n\t\tif err != nil {\n\t\t\tctx.jsAlert(\"save failed,err:\" + err.Error())\n\t\t} else {\n\t\t\tctx.w.Write([]byte(\"<script>alert('save success');top.location.href='/config'</script>\"))\n\t\t}\n\t}\n}\n\nfunc (ctx *webRequestCtx) handle_response() {\n\tdocid, uintParseErr := parseDocID(ctx.req.FormValue(\"id\"))\n\tif uintParseErr == nil {\n\t\tresponseData, _ := ctx.ser.getResponseByDocid(docid)\n\t\tif responseData == nil {\n\t\t\tctx.showError(\"response not found\")\n\t\t} else {\n\t\t\twalker := object.NewInterfaceWalker(map[string]any(responseData.Data))\n\t\t\tvar contentType string\n\t\t\tif typeHeader, has := walker.GetStringSlice(\"/header/Content-Type\"); has {\n\t\t\t\tcontentType = strings.Join(typeHeader, \";\")\n\t\t\t}\n\n\t\t\tcustomContentType := ctx.req.FormValue(\"type\")\n\t\t\t// set custom content type\n\t\t\tif customContentType != \"\" {\n\t\t\t\tswitch customContentType {\n\t\t\t\tcase \"json\":\n\t\t\t\t\tcontentType = \"application/json\"\n\t\t\t\tcase \"html\":\n\t\t\t\t\tcontentType = \"text/html;charset=utf-8\"\n\t\t\t\tdefault:\n\t\t\t\t\tcontentType = customContentType\n\t\t\t\t}\n\t\t\t}\n\t\t\tif contentType != \"\" {\n\t\t\t\tctx.w.Header().Set(\"Content-Type\", contentType)\n\t\t\t}\n\t\t\tif statusCode, has := walker.GetInt(\"/status\"); has {\n\t\t\t\tctx.w.WriteHeader(statusCode)\n\t\t\t}\n\t\t\tif bodyStr, has := walker.GetString(\"/body\"); has {\n\t\t\t\tbodyByte, err := base64.StdEncoding.DecodeString(bodyStr)\n\t\t\t\tif err == nil {\n\t\t\t\t\tctx.w.Write(bodyByte)\n\t\t\t\t} else {\n\t\t\t\t\tlog.Println(\"decode body failed\", err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tctx.showError(\"response body not found\")\n\t\t\t}\n\t\t}\n\t} else {\n\t\tctx.showError(\"param err\")\n\t}\n}\n\nfunc (ctx *webRequestCtx) jsAlert(msg string) {\n\tfmt.Fprintf(ctx.w, \"<script>alert('%s')</script>\", html.EscapeString(msg))\n}\n\nfunc (ctx *webRequestCtx) jsAlertJump(msg string, urlStr string) {\n\tfmt.Fprintf(ctx.w, \"<script>alert('%s');top.location.href='%s'</script>\", html.EscapeString(msg), urlStr)\n}\n\nfunc (ctx *webRequestCtx) handle_about() {\n\tctx.render(\"about.html\", true)\n}\n\nfunc (ctx *webRequestCtx) handle_logout() {\n\tcookie := &http.Cookie{Name: cookieName, Value: \"\", Path: \"/\"}\n\thttp.SetCookie(ctx.w, cookie)\n\thttp.Redirect(ctx.w, ctx.req, \"/\", 302)\n}\n\nfunc (ctx *webRequestCtx) handle_login() {\n\tif ctx.req.Method == \"GET\" {\n\t\tctx.render(\"login.html\", true)\n\t} else {\n\t\tname := strings.TrimSpace(ctx.req.FormValue(\"name\"))\n\t\tpsw := strings.TrimSpace(ctx.req.FormValue(\"psw\"))\n\t\tif name == \"\" {\n\t\t\tctx.jsAlert(\"empty name\")\n\t\t\treturn\n\t\t}\n\t\tif user, has := ctx.ser.Users[name]; has {\n\t\t\tif user.isPswEq(psw) {\n\t\t\t\tlog.Println(\"login suc,name=\", name)\n\t\t\t\tcookie := &http.Cookie{\n\t\t\t\t\tName:    cookieName,\n\t\t\t\t\tValue:   fmt.Sprintf(\"%s:%s\", name, user.PswMd5),\n\t\t\t\t\tPath:    \"/\",\n\t\t\t\t\tExpires: time.Now().Add(86400 * time.Second),\n\t\t\t\t}\n\t\t\t\thttp.SetCookie(ctx.w, cookie)\n\t\t\t\tctx.w.Write([]byte(\"<script>parent.location.href='/'</script>\"))\n\t\t\t} else {\n\t\t\t\tlog.Println(\"login failed psw incorrect,name=\", name, \"psw=\", psw)\n\t\t\t\tctx.jsAlert(\"password incorrect\")\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tlog.Println(\"login failed not exists,name=\", name, \"psw=\", psw)\n\t\tctx.jsAlert(\"user not exists\")\n\t}\n}\n\nfunc (ctx *webRequestCtx) render(name string, layout bool) {\n\thtml := render_html(name, ctx.values, layout)\n\tctx.w.Write([]byte(html))\n}\n\nfunc (ctx *webRequestCtx) showError(msg string) {\n\tctx.values[\"error\"] = msg\n\tctx.values[\"subTitle\"] = \"Error Page |\"\n\tctx.render(\"error.html\", true)\n}\n\nfunc (ctx *webRequestCtx) showErrorOrAlert(msg string) {\n\tif ctx.req.Method == \"POST\" {\n\t\tctx.jsAlert(msg)\n\t} else {\n\t\tctx.showError(msg)\n\t}\n}\n\nfunc reader_html_include(fileName string) string {\n\thtml := Assest.GetContent(\"/res/tpl/\" + fileName)\n\tmyfn := template.FuncMap{\n\t\t\"my_include\": func(name string) string {\n\t\t\treturn reader_html_include(name)\n\t\t},\n\t}\n\ttpl, _ := template.New(\"page_include\").Delims(\"{%\", \"%}\").Funcs(myfn).Parse(html)\n\tvar bf []byte\n\tw := bytes.NewBuffer(bf)\n\ttpl.Execute(w, make(map[string]string))\n\tbody := w.String()\n\treturn body\n}\n\nfunc render_html(fileName string, values map[string]any, layout bool) string {\n\thtml := reader_html_include(fileName)\n\tfuncs := template.FuncMap{\n\t\t\"escape\": func(str string) string {\n\t\t\treturn url.QueryEscape(str)\n\t\t},\n\t\t\"my_include\": func(fileName string) string {\n\t\t\treturn \"include (\" + fileName + \") with Delims {%my_include %}\"\n\t\t},\n\t}\n\ttpl, _ := template.New(\"page\").Funcs(funcs).Parse(html)\n\tvar bf []byte\n\tw := bytes.NewBuffer(bf)\n\ttpl.Execute(w, values)\n\tbody := w.String()\n\tif layout {\n\t\tvalues[\"body\"] = body\n\t\treturn render_html(\"layout.html\", values, false)\n\t}\n\treturn html_util.Html_reduceSpace(body)\n}\n\nfunc (ser *ProxyServe) handleUserInfo(w http.ResponseWriter, req *http.Request) {\n\thost, _, _ := net.SplitHostPort(req.RemoteAddr)\n\tdata := \"client ip:\" + host\n\tw.Write([]byte(data))\n}\n"
  },
  {
    "path": "serve/web_file.go",
    "content": "package serve\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/hidu/goutils/fs\"\n)\n\ntype webFileInfo struct {\n\tName         string\n\tRootDir      string\n\tIsDir        bool\n\tSize         int64\n\tLink         string\n\tfullPath     string\n\tfile         *os.File\n\tsubFileInfos []*webFileInfo\n}\n\nfunc newWebFileInfo(rootDir, name string) (*webFileInfo, error) {\n\trootDir = filepath.Clean(rootDir + \"/\")\n\tfullPath := filepath.Clean(fmt.Sprintf(\"%s/%s\", rootDir, name))\n\tif !strings.HasPrefix(fullPath, rootDir) {\n\t\treturn nil, fmt.Errorf(\"unsafe path:%s\", name)\n\t}\n\tf, err := os.Open(fullPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tstat, err := f.Stat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tinfo := &webFileInfo{\n\t\tName:     strings.TrimLeft(fullPath[len(rootDir):], \"/\"),\n\t\tRootDir:  rootDir,\n\t\tIsDir:    stat.IsDir(),\n\t\tSize:     stat.Size(),\n\t\tfullPath: fullPath,\n\t\tfile:     f,\n\t}\n\tinfo.Link = info.link()\n\treturn info, nil\n}\n\nfunc (f *webFileInfo) String() string {\n\treturn fmt.Sprintf(\"Name:%s\\nRootDir:%s\\nisDir:%v\\nSize:%d\\nfullPath:%s\\n\", f.Name, f.RootDir, f.IsDir, f.Size, f.fullPath)\n}\n\nfunc (f *webFileInfo) link() string {\n\tvalues := make(url.Values)\n\tvalues.Set(\"name\", f.Name)\n\tif !f.IsDir {\n\t\tvalues.Set(\"op\", \"edit\")\n\t}\n\treturn \"/file?\" + values.Encode()\n}\n\nfunc (f *webFileInfo) getContent() string {\n\tif f.IsDir {\n\t\treturn \"\"\n\t}\n\tdata, err := io.ReadAll(f.file)\n\tif err != nil {\n\t\tlog.Println(\"read file failed:\", err)\n\t\treturn \"\"\n\t}\n\treturn string(data)\n}\n\nfunc (f *webFileInfo) Close() {\n\tf.file.Close()\n\tif f.subFileInfos != nil {\n\t\tfor _, info := range f.subFileInfos {\n\t\t\tinfo.Close()\n\t\t}\n\t}\n}\n\nfunc (f *webFileInfo) subFiles() ([]*webFileInfo, error) {\n\tnames, err := f.file.Readdirnames(0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfileInfos := make([]*webFileInfo, 0)\n\n\tfor _, name := range names {\n\t\tinfo, err := newWebFileInfo(f.RootDir, fmt.Sprintf(\"%s/%s\", f.Name, name))\n\t\tif err != nil {\n\t\t\tlog.Println(\"read file err,skip.name=\", name, err)\n\t\t} else {\n\t\t\tfileInfos = append(fileInfos, info)\n\t\t}\n\t}\n\tf.subFileInfos = fileInfos\n\treturn fileInfos, nil\n}\n\nfunc (ser *ProxyServe) getWebFilePath(name string) (fullPath string, nameNew string, err error) {\n\trootDir := filepath.Clean(ser.conf.FileDir + \"/\")\n\tfullPath = filepath.Clean(fmt.Sprintf(\"%s/%s\", rootDir, name))\n\tif !strings.HasPrefix(fullPath, rootDir) {\n\t\treturn \"\", \"\", fmt.Errorf(\"unsafe path:%s\", name)\n\t}\n\tnameNew = fullPath[len(rootDir):]\n\tre := regexp.MustCompile(`^[\\w/\\-\\.]*$`)\n\tif !re.MatchString(nameNew) {\n\t\terr = fmt.Errorf(\"illegal path:%s\", nameNew)\n\t}\n\treturn fullPath, nameNew, err\n}\n\nfunc (ctx *webRequestCtx) handle_file() {\n\tif !ctx.isLogin {\n\t\tctx.showError(\"need login\")\n\t\treturn\n\t}\n\n\topMap := make(map[string]func())\n\topMap[\"edit\"] = ctx.handle_file_edit\n\topMap[\"new\"] = ctx.handle_file_new\n\topMap[\"del\"] = ctx.handle_file_del\n\topMap[\"save\"] = ctx.handle_file_save\n\n\top := ctx.req.FormValue(\"op\")\n\tif fn, has := opMap[op]; has {\n\t\tfn()\n\t\treturn\n\t}\n\tname := ctx.req.FormValue(\"name\")\n\tif !ctx.isAdmin && name == \"\" {\n\t\tname = ctx.user.Name\n\t\tdirFullPath, _, err := ctx.ser.getWebFilePath(name)\n\t\tif err != nil {\n\t\t\tctx.showError(\"file dir wrong\")\n\t\t\treturn\n\t\t}\n\t\tif !fs.FileExists(dirFullPath) {\n\t\t\tos.MkdirAll(dirFullPath, os.ModePerm)\n\t\t}\n\t}\n\n\tdirInfo, err := newWebFileInfo(ctx.ser.conf.FileDir, name)\n\tif err != nil {\n\t\tctx.showError(\"open file dir failed:\" + name)\n\t\treturn\n\t}\n\tdefer dirInfo.Close()\n\n\tctx.values[\"currentDir\"] = dirInfo.Name\n\tctx.values[\"isSubDir\"] = dirInfo.Name != \"\"\n\tif !ctx.isAdmin && !strings.Contains(dirInfo.Name, \"/\") {\n\t\tctx.values[\"isSubDir\"] = false\n\t}\n\tfiles, err := dirInfo.subFiles()\n\tif err != nil {\n\t\tctx.showError(err.Error())\n\t\treturn\n\t}\n\tctx.values[\"files\"] = files\n\n\tctx.render(\"file.html\", true)\n}\n\nfunc (ctx *webRequestCtx) handle_file_edit() {\n\tname := ctx.req.FormValue(\"name\")\n\tif name == \"\" {\n\t\tctx.showError(\"params wrong\")\n\t\treturn\n\t}\n\tinfo, err := newWebFileInfo(ctx.ser.conf.FileDir, name)\n\tif err != nil {\n\t\tctx.showError(\"read file info failed:\" + err.Error())\n\t\treturn\n\t}\n\tdefer info.Close()\n\tif info.IsDir {\n\t\tctx.showError(\"params wrong,only file can view\")\n\t\treturn\n\t}\n\tctx.values[\"file\"] = info\n\tfileContent := info.getContent()\n\tctx.values[\"fileContent\"] = fileContent\n\tctx.values[\"fileContentRows\"] = len(strings.Split(fileContent, \"\\n\")) + 8\n\tctx.render(\"file_edit.html\", true)\n}\n\nfunc (ctx *webRequestCtx) handle_file_del() {}\n\nfunc (ctx *webRequestCtx) handle_file_new() {\n\tdirFullPath, dirNew, err := ctx.ser.getWebFilePath(ctx.req.FormValue(\"dir\"))\n\tif err != nil {\n\t\tctx.showErrorOrAlert(\"params err:\" + err.Error())\n\t\treturn\n\t}\n\tctx.values[\"dir\"] = dirNew\n\n\tif ctx.req.Method == \"GET\" {\n\t\tfinfo, fErr := os.Stat(dirFullPath)\n\t\tif fErr != nil || !finfo.IsDir() {\n\t\t\tctx.showErrorOrAlert(\"open dir failed\")\n\t\t\treturn\n\t\t}\n\t\tctx.render(\"file_new.html\", true)\n\t} else if ctx.req.Method == \"POST\" {\n\t\tname := strings.TrimSpace(ctx.req.FormValue(\"name\"))\n\t\tif name == \"\" {\n\t\t\tctx.jsAlert(\"empty filename\")\n\t\t\treturn\n\t\t}\n\t\tfpath := ctx.req.FormValue(\"dir\") + \"/\" + ctx.req.FormValue(\"name\")\n\n\t\tfileFullPath, fileName, err := ctx.ser.getWebFilePath(fpath)\n\n\t\tif err != nil {\n\t\t\tctx.jsAlert(\"wrong fileName\")\n\t\t\treturn\n\t\t}\n\n\t\tif fileName == \"\" || strings.HasSuffix(fileName, \"/\") {\n\t\t\tctx.jsAlert(\"wrong file name\")\n\t\t\treturn\n\t\t}\n\n\t\tif fs.FileExists(fileFullPath) {\n\t\t\tctx.jsAlert(\"file already exists\")\n\t\t\treturn\n\t\t}\n\n\t\tif !strings.HasPrefix(fileFullPath, dirFullPath) {\n\t\t\tctx.jsAlert(\"file name wrong\")\n\t\t\treturn\n\t\t}\n\n\t\tif !ctx.user.IsAdmin && !strings.HasPrefix(fileName+\"/\", \"/\"+ctx.user.Name+\"/\") {\n\t\t\tctx.jsAlert(\"file path wrong:\" + fileName)\n\t\t\treturn\n\t\t}\n\n\t\tdirName := filepath.Dir(fileFullPath)\n\t\tif !fs.FileExists(dirName) {\n\t\t\tos.MkdirAll(dirName, os.ModePerm)\n\t\t}\n\t\tcontent := ctx.req.FormValue(\"content\")\n\n\t\twErr := fs.FilePutContents(fileFullPath, []byte(content))\n\t\tif wErr != nil {\n\t\t\tctx.jsAlert(\"write file failed\")\n\t\t\treturn\n\t\t}\n\n\t\tfinfo, _ := newWebFileInfo(ctx.ser.conf.FileDir, fpath)\n\t\tdefer finfo.Close()\n\n\t\tctx.jsAlertJump(\"save suc\", finfo.link())\n\t}\n}\n\nfunc (ctx *webRequestCtx) handle_file_save() {\n\tnameOrigin := ctx.req.PostFormValue(\"nameOrigin\")\n\tname := ctx.req.PostFormValue(\"name\")\n\tcontent := ctx.req.PostFormValue(\"content\")\n\n\tfullPath, nameFix, err := ctx.ser.getWebFilePath(name)\n\tif err != nil {\n\t\tctx.jsAlert(\"file path wrong:\" + err.Error())\n\t\treturn\n\t}\n\tif name == \"\" || nameFix == \"\" || strings.HasSuffix(nameFix, \"/\") {\n\t\tctx.jsAlert(\"wrong file name\")\n\t\treturn\n\t}\n\tfullPathOrigin, _, err := ctx.ser.getWebFilePath(nameOrigin)\n\n\tif fullPathOrigin == \"\" && err != nil {\n\t\tctx.jsAlert(\"origin file path wrong:\" + err.Error())\n\t\treturn\n\t}\n\n\tdirName := filepath.Dir(fullPath)\n\tif !fs.FileExists(dirName) {\n\t\tos.MkdirAll(dirName, os.ModePerm)\n\t}\n\n\terrWrite := fs.FilePutContents(fullPath, []byte(content))\n\tif errWrite != nil {\n\t\tctx.jsAlert(\"save failed:\" + errWrite.Error())\n\t\treturn\n\t}\n\tif fullPath != fullPathOrigin {\n\t\tos.Remove(fullPathOrigin)\n\t}\n\tinfo, _ := newWebFileInfo(ctx.ser.conf.FileDir, name)\n\tctx.jsAlertJump(\"save suc\", info.link())\n}\n"
  },
  {
    "path": "serve/wsClient.go",
    "content": "package serve\n\nimport (\n\t\"net/http\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/googollee/go-socket.io\"\n)\n\ntype wsClient struct {\n\tns            *socketio.NameSpace\n\tuser          string\n\tfilterUser    []string\n\tfilterIP      []string\n\tfilterHideExt []string\n\tfilterURL     []string\n\tfilterURLHide []string\n\tLoginUser     *User\n}\n\nvar extTypes = map[string][]string{\n\t\"js\":    {\"js\"},\n\t\"css\":   {\"css\"},\n\t\"image\": {\"jpg\", \"jpeg\", \"png\", \"gif\", \"bmp\", \"tiff\", \"jpe\", \"tif\", \"webp\", \"ico\", \"webp\"},\n}\n\nfunc (client *wsClient) checkFilter(req *http.Request, reqCtx *requestCtx) bool {\n\tif len(client.filterUser) > 0 {\n\t\tuserInList := false\n\t\tfor _, name := range client.filterUser {\n\t\t\tif name == \"any\" && client.LoginUser != nil && client.LoginUser.IsAdmin {\n\t\t\t\tuserInList = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif name != \"\" && name == reqCtx.User.Name {\n\t\t\t\tuserInList = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !userInList {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif len(client.filterIP) > 0 {\n\t\taddrInfo := strings.Split(reqCtx.RemoteAddr, \":\")\n\t\tipInList := false\n\t\tfor _, ip := range client.filterIP {\n\t\t\tif ip == \"*\" {\n\t\t\t\tipInList = true\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif ip != \"\" && addrInfo[0] == ip {\n\t\t\t\tipInList = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !ipInList {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif len(client.filterURL) > 0 {\n\t\turl := req.URL.String()\n\t\thasKw := false\n\t\tfor _, subURL := range client.filterURL {\n\t\t\tif strings.Contains(url, subURL) {\n\t\t\t\thasKw = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !hasKw {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif len(client.filterHideExt) > 0 {\n\t\text := strings.ToLower(strings.Trim(filepath.Ext(req.URL.Path), \".\"))\n\t\tfor _, hideType := range client.filterHideExt {\n\t\t\tfor _, hideExt := range extTypes[hideType] {\n\t\t\t\tif ext == hideExt {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif len(client.filterURLHide) > 0 {\n\t\t_url := req.URL.String()\n\t\tfor _, hideKw := range client.filterURLHide {\n\t\t\tif hideKw != \"\" && strings.Contains(_url, hideKw) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "serve/wsServer.go",
    "content": "package serve\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sync\"\n\n\t\"github.com/googollee/go-socket.io\"\n\t\"github.com/hidu/goutils/time_util\"\n)\n\ntype wsServer struct {\n\tclients  map[string]*wsClient\n\tserver   *socketio.SocketIOServer\n\tmu       sync.RWMutex\n\tproxySer *ProxyServe\n}\n\nfunc (ser *ProxyServe) wsInit() {\n\tser.wsSer = newWsServer(ser)\n}\n\nfunc newWsServer(ser *ProxyServe) *wsServer {\n\twsSer := &wsServer{\n\t\tclients:  make(map[string]*wsClient),\n\t\tproxySer: ser,\n\t}\n\tvar err error\n\twsSer.server = socketio.NewSocketIOServer(&socketio.Config{})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\twsSer.init()\n\treturn wsSer\n}\n\nfunc (wsSer *wsServer) init() {\n\twsSer.server.On(\"connect\", func(ns *socketio.NameSpace) {\n\t\twsSer.mu.Lock()\n\t\tdefer wsSer.mu.Unlock()\n\t\twsSer.clients[ns.Id()] = &wsClient{ns: ns, user: \"guest\"}\n\t\tlog.Println(\"ws connected\", ns.Id(), \"ws_client_num:\", len(wsSer.clients))\n\t})\n\twsSer.server.On(\"disconnect\", func(ns *socketio.NameSpace) {\n\t\twsSer.remove(ns.Id())\n\t\tlog.Println(\"ws disconnect\", ns.Id(), \"ws_client_num:\", len(wsSer.clients))\n\t})\n\twsSer.server.On(\"error\", func(ns *socketio.NameSpace, err error) {\n\t\tlog.Println(\"ws error:\", err)\n\t})\n\twsSer.server.On(\"get_response\", wsSer.getResponse)\n\twsSer.server.On(\"client_filter\", wsSer.saveFilter)\n\n\ttime_util.SetInterval(func() {\n\t\twsSer.broadcast(\"hello\", \"hello\", false)\n\t}, 120)\n}\n\nfunc (wsSer *wsServer) remove(id string) {\n\twsSer.mu.Lock()\n\tdefer wsSer.mu.Unlock()\n\tif _, has := wsSer.clients[id]; has {\n\t\tdelete(wsSer.clients, id)\n\t}\n}\n\nfunc (wsSer *wsServer) broadProxyClientNum() {\n\twsSer.broadcast(\"user_num\", len(wsSer.proxySer.ProxyClients), false)\n}\n\n/*\n * https://github.com/googollee/go-socket.io\n */\nfunc (wsSer *wsServer) getResponse(ns *socketio.NameSpace, docidStr string) {\n\tdocid, uintParseErr := parseDocID(docidStr)\n\tif uintParseErr != nil {\n\t\tlog.Println(\"parse str2int failed\", docidStr, uintParseErr)\n\t\treturn\n\t}\n\tlog.Println(\"receive docid\", docid)\n\treq, _ := wsSer.proxySer.getRequestByDocid(docid)\n\tres, _ := wsSer.proxySer.getResponseByDocid(docid)\n\tif wsSer.proxySer.Debug {\n\t\tfmt.Println(\"req:\\n\", req, \"\\n==========\\n\")\n\t\tfmt.Println(\"res:\\n\", res, \"\\n==========\\n\")\n\t}\n\t// \tdelete(req,\"header\")\n\tdata := make(map[string]any)\n\tdata[\"req\"] = nil\n\tdata[\"res\"] = nil\n\tif req != nil {\n\t\tdata[\"req\"] = req.Data\n\t}\n\tif res != nil {\n\t\tdata[\"res\"] = res.Data\n\t}\n\twsSer.send(ns, \"res\", data, true)\n}\n\nfunc (wsSer *wsServer) saveFilter(ns *socketio.NameSpace, formData string) {\n\tm, err := url.ParseQuery(formData)\n\tif err != nil {\n\t\tlog.Println(\"parse filter data err\", err)\n\t\treturn\n\t}\n\twsSer.mu.Lock()\n\tdefer wsSer.mu.Unlock()\n\tif nsClient, has := wsSer.clients[ns.Id()]; has {\n\t\tnsClient.filterIP = parseURLInputAsSlice(m.Get(\"client_ip\"))\n\t\tnsClient.filterHideExt = m[\"hide\"]\n\t\tnsClient.filterURL = parseURLInputAsSlice(m.Get(\"url_match\"))\n\t\tnsClient.filterURLHide = parseURLInputAsSlice(m.Get(\"hide_url\"))\n\t\tnsClient.filterUser = parseURLInputAsSlice(m.Get(\"user\"))\n\t\tloginUser, isLogin := wsSer.proxySer.web_checkLogin(ns.Session.Request)\n\t\tif isLogin {\n\t\t\tnsClient.LoginUser = loginUser\n\t\t}\n\t} else {\n\t\tlog.Println(\"ws_saveFilter failed,ws not exists\")\n\t}\n}\n\nvar nnnn int\n\nfunc (wsSer *wsServer) send(ns *socketio.NameSpace, msgName string, data any, encode bool) {\n\twsSer.mu.Lock()\n\n\tdefer func(ns *socketio.NameSpace) {\n\t\twsSer.mu.Unlock()\n\t\tif e := recover(); e != nil {\n\t\t\tlog.Println(\"ws_send failed\", e, ns.Session.Request.RemoteAddr, \"msgName:\", msgName, \"client:\", len(wsSer.clients))\n\t\t\twsSer.remove(ns.Id())\n\t\t}\n\t}(ns)\n\tvar err error\n\tencode = false\n\tif encode {\n\t\terr = ns.Emit(msgName, dataEncode(data))\n\t} else {\n\t\terr = ns.Emit(msgName, data)\n\t}\n\tif err != nil {\n\t\tlog.Println(\"emit_failed\", msgName, err)\n\t}\n}\n\nfunc (wsSer *wsServer) broadcastReq(req *http.Request, reqCtx *requestCtx, data any) bool {\n\twsSer.mu.RLock()\n\tdefer wsSer.mu.RUnlock()\n\n\thasSend := false\n\tfor _, client := range wsSer.clients {\n\t\tif wsSer.proxySer.conf.SessionView == sessionViewIPOrUser && len(client.filterIP) == 0 && len(client.filterUser) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif reqCtx.User.Name != \"\" && len(client.filterUser) < 1 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif client.checkFilter(req, reqCtx) {\n\t\t\tgo wsSer.send(client.ns, \"req\", data, true)\n\t\t\thasSend = true\n\t\t}\n\t}\n\treturn hasSend\n}\n\nfunc (wsSer *wsServer) broadcast(name string, data any, encode bool) {\n\twsSer.mu.RLock()\n\tdefer wsSer.mu.RUnlock()\n\tfor _, client := range wsSer.clients {\n\t\tgo wsSer.send(client.ns, name, data, encode)\n\t}\n}\n"
  }
]