├── .gitignore ├── .jshintrc ├── .travis.yml ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── LICENSE.txt ├── README.md ├── lib ├── crawler.js └── debug.js ├── package.json ├── tests ├── cacheOption.test.js ├── encoding.test.js ├── errorHandling.test.js ├── examples.test.js ├── jqueryOption.test.js ├── linksResolving.test.js ├── memoryLeaks.test.js ├── rateLimitsOption.test.js ├── requests.test.js └── uriOption.test.js ├── travis_scripts └── before_install.sh └── vendor ├── jquery-1.11.1.min.js └── jquery-2.1.1.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .idea/ 4 | npm-debug.log -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise" : true, 3 | "camelcase" : true, 4 | "curly" : true, 5 | "eqeqeq" : true, 6 | "freeze" : true, 7 | "forin" : true, 8 | "immed" : false, 9 | "indent" : 4, 10 | "latedef" : false, 11 | "newcap" : false, 12 | "noarg" : true, 13 | "noempty" : true, 14 | "nonbsp" : true, 15 | "nonew" : false, 16 | "plusplus" : false, 17 | "quotmark" : "single", 18 | "undef" : true, 19 | "unused" : true, 20 | "strict" : true, 21 | "maxparams" : false, 22 | "maxdepth" : false, 23 | "maxstatements" : false, 24 | "maxcomplexity" : false, 25 | "maxlen" : 120, 26 | 27 | "asi" : false, 28 | "boss" : false, 29 | "debug" : false, 30 | "eqnull" : false, 31 | "es5" : false, 32 | "esnext" : false, 33 | "moz" : false, 34 | "evil" : false, 35 | "expr" : true, 36 | "funcscope" : false, 37 | "globalstrict" : false, 38 | "iterator" : false, 39 | "lastsemic" : false, 40 | "laxbreak" : false, 41 | "laxcomma" : false, 42 | "loopfunc" : false, 43 | "multistr" : false, 44 | "noyield" : false, 45 | "notypeof" : false, 46 | "proto" : false, 47 | "scripturl" : false, 48 | "shadow" : false, 49 | "sub" : false, 50 | "supernew" : false, 51 | "validthis" : false, 52 | 53 | "devel" : true, 54 | "mocha" : true, 55 | "node" : true, 56 | 57 | "globals" : {} 58 | } 59 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: required 3 | node_js: 4 | - 0.10 5 | - 0.12 6 | os: 7 | - linux 8 | - osx 9 | before_install: 10 | - sh ./travis_scripts/before_install.sh 11 | 12 | matrix: 13 | allow_failures: 14 | - os: osx -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | node-webcrawler ChangeLog 2 | ------------------------- 3 | 4 | 0.5.0 version changelog: 5 | * parse charset from `content-type` in http headers or meta tag in html, then convert 6 | * big5 charset is avaliable as the `iconv-lite` has already supported it 7 | * default enable gzip in request header 8 | * remove unzip code in crawler since `request` will do this 9 | * body will return as a Buffer if encoding is null which is an option in `request` 10 | * remove cache and skip duplicate `request` for `GET`, `POST`(only for type `urlencode`), `HEAD` 11 | * add log feature, you can use `winston` to set `logger:winston`, or crawler will output to console 12 | * rotate user-agent in case some sites ban your requests 13 | 14 | 0.5.1 version changelog: 15 | * remove cache feature, it's useless 16 | * add `localAddress`, `time`, `tunnel`, `proxyHeaderWhiteList`, `proxyHeaderExclusiveList` properties to pass to `request` 17 | 18 | 0.5.2 version changelog: 19 | * you can manually terminate all the resources in your pool, when `onDrain` called, before their timeouts have been reached 20 | * add a read-only property `queueSize` to crawler 21 | 22 | 0.6.0 version changelog: 23 | * add `bottleneck` to implement rate limit, one can set limit for each connection at same time. 24 | 25 | 0.6.3 version changelog: 26 | * you could also get `result.options` from callback even when some errors ouccurred 27 | * add test for `bottleneck` 28 | 29 | 0.6.5 30 | * fix a deep and big bug when initializing Pool, that may lead to sequence execution. [issue](https://github.com/bda-research/node-webcrawler/issues/2) 31 | * print log of Pool status 32 | 33 | 0.6.9 34 | * use `bottleneckConcurrent` instead of `maxConnections`, default `10000` 35 | * add debug info 36 | 37 | 0.7.0 38 | * cancel recursion in queue 39 | * upgrade `request` version to v2.67.0 40 | 41 | 0.7.4 42 | * change `debug` option to instance level instead of `options` 43 | * update README.md to detail error handling 44 | * call `onDrain` with scope of `this` 45 | * upgrade `seenreq` version to 0.1.7 46 | 47 | 0.7.5 48 | * delete entity in options before copy, and assgin after, `jar` is one of the typical properties which is an `Entity` wich functions 49 | * upgrade `request` to version 2.74.0 50 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Docker images 2 | # https://registry.hub.docker.com/_/node/ 3 | # 4 | FROM node:0.12.7 5 | 6 | RUN apt-get update 7 | 8 | RUN apt-get install -y python python-pip 9 | 10 | RUN pip install httpbin gunicorn -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Mike Chen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Sylvain Zimmer 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![build status](https://secure.travis-ci.org/bda-research/node-webcrawler.png)](https://travis-ci.org/bda-research/node-webcrawler) 2 | This repo is merged with [node-crawler](https://github.com/bda-research/node-crawler), please use it instead. 3 | ------------ 4 | 5 | Features: 6 | * server-side DOM & automatic jQuery insertion with Cheerio (default) or JSDOM 7 | * Configurable pool size and retries 8 | * Priority of requests 9 | * forceUTF8 mode to let crawler deal for you with charset detection and conversion 10 | 11 | Here is the [CHANGELOG](https://github.com/bda-research/node-webcrawler/blob/master/CHANGELOG.md) 12 | 13 | Help & Forks welcomed! 14 | 15 | How to install 16 | -------------- 17 | 18 | $ npm install node-webcrawler 19 | 20 | Crash course 21 | ------------ 22 | 23 | ```javascript 24 | var Crawler = require("node-webcrawler"); 25 | var url = require('url'); 26 | 27 | var c = new Crawler({ 28 | maxConnections : 10, 29 | // This will be called for each crawled page 30 | callback : function (error, result, $) { 31 | // $ is Cheerio by default 32 | //a lean implementation of core jQuery designed specifically for the server 33 | if(error){ 34 | console.log(error); 35 | }else{ 36 | console.log($("title").text()); 37 | } 38 | } 39 | }); 40 | 41 | // Queue just one URL, with default callback 42 | c.queue('http://www.amazon.com'); 43 | 44 | // Queue a list of URLs 45 | c.queue(['http://www.google.com/','http://www.yahoo.com']); 46 | 47 | // Queue URLs with custom callbacks & parameters 48 | c.queue([{ 49 | uri: 'http://parishackers.org/', 50 | jQuery: false, 51 | 52 | // The global callback won't be called 53 | callback: function (error, result) { 54 | if(error){ 55 | console.log(error); 56 | }else{ 57 | console.log('Grabbed', result.body.length, 'bytes'); 58 | } 59 | } 60 | }]); 61 | 62 | // Queue some HTML code directly without grabbing (mostly for tests) 63 | c.queue([{ 64 | html: '

This is a test

' 65 | }]); 66 | ``` 67 | 68 | Work with `bottleneck` 69 | -------------------- 70 | Control rate limits for each connection, usually used with proxy. 71 | 72 | ```javascript 73 | var Crawler = require("node-webcrawler"); 74 | 75 | var c = new Crawler({ 76 | maxConnections : 3, 77 | rateLimits:2000, 78 | callback : function (error, result, $) { 79 | if(error){ 80 | console.error(error); 81 | }else{ 82 | console.log($('title').text()); 83 | } 84 | } 85 | }); 86 | 87 | c.queue({ 88 | uri:"http://www.google.com", 89 | limiter:"key1",// for connection of 'key1' 90 | proxy:"http://user:pass@127.0.0.1:8080" 91 | }); 92 | 93 | c.queue({ 94 | uri:"http://www.google.com", 95 | limiter:"key2", // for connection of 'key2' 96 | proxy:"http://user:pass@127.0.0.1:8082" 97 | }); 98 | 99 | c.queue({ 100 | uri:"http://www.google.com", 101 | limiter:"key3", // for connection of 'key3' 102 | proxy:"http://user:pass@127.0.0.1:8081" 103 | }); 104 | 105 | ``` 106 | 107 | Options reference 108 | ----------------- 109 | 110 | You can pass these options to the Crawler() constructor if you want them to be global or as 111 | items in the queue() calls if you want them to be specific to that item (overwriting global options) 112 | 113 | This options list is a strict superset of [mikeal's request options](https://github.com/mikeal/request#requestoptions-callback) and will be directly passed to 114 | the request() method. 115 | 116 | Basic request options: 117 | 118 | * `uri`: String, the URL you want to crawl 119 | * `timeout` : Number, in milliseconds (Default 15000) 120 | * [All mikeal's requests options are accepted](https://github.com/mikeal/request#requestoptions-callback) 121 | 122 | Callbacks: 123 | 124 | * `callback(error, result, $)`: A request was completed 125 | * `onDrain(pool)`: There is no more queued requests, call `pool.destroyAllNow()` if you wanna release resources in pool to, or if you have follow-up tasks to queue you can ignore. 126 | 127 | Pool options: 128 | 129 | * `maxConnections`: Number, Size of the worker pool (Default 10), 130 | * `priorityRange`: Number, Range of acceptable priorities starting from 0 (Default 10), 131 | * `priority`: Number, Priority of this request (Default 5), 132 | 133 | Retry options: 134 | 135 | * `retries`: Number of retries if the request fails (Default 3), 136 | * `retryTimeout`: Number of milliseconds to wait before retrying (Default 10000), 137 | 138 | Server-side DOM options: 139 | 140 | * `jQuery`: true, false or ConfObject (Default true) 141 | 142 | Charset encoding: 143 | 144 | * `forceUTF8`: Boolean, if true will get charset from HTTP headers or meta tag in html and convert it to UTF8 if necessary. Never worry about encoding anymore! (Default false), 145 | * `incomingEncoding`: String, with forceUTF8: true to set encoding manually (Default null) 146 | `incomingEncoding : 'windows-1255'` for example 147 | 148 | Cache: 149 | 150 | * `cache`: Boolean, if true stores requests' result in memory (Default false), not recommend if you are doing with huge amount of pages as the process will exhaust momery 151 | * `skipDuplicates`: Boolean, if true skips URIs that were already crawled, without even calling callback() (Default false) 152 | 153 | Other: 154 | * `rotateUA`: Boolean, if true, `userAgent` should be an array, and rotate it (Default false) 155 | * `userAgent`: String or Array, if `rotateUA` is false, but `userAgent` is array, will use first one. 156 | * `referer`: String, if truthy sets the HTTP referer header 157 | * `rateLimits`: Number of milliseconds to delay between each requests (Default 0) 158 | 159 | 160 | Class:Crawler 161 | ------------- 162 | 163 | Instance of Crawler 164 | 165 | __crawler.queue(uri|options)__ 166 | * `uri` String, `options` is [Options](#options-reference) 167 | 168 | __crawler.queueSize__ 169 | 170 | Size of queue, read-only 171 | 172 | 173 | Working with Cheerio or JSDOM 174 | ----------------------------- 175 | 176 | Crawler by default use [Cheerio](https://github.com/cheeriojs/cheerio) instead of [Jsdom](https://github.com/tmpvar/jsdom). Jsdom is more robust but can be hard to install (espacially on windows) because of [contextify](https://github.com/tmpvar/jsdom#contextify). 177 | Which is why, if you want to use jsdom you will have to build it, and `require('jsdom')` in your own script before passing it to crawler. This is to avoid cheerio crawler user to build jsdom when installing crawler. 178 | 179 | ###Working with Cheerio 180 | ```javascript 181 | jQuery: true //(default) 182 | //OR 183 | jQuery: 'cheerio' 184 | //OR 185 | jQuery: { 186 | name: 'cheerio', 187 | options: { 188 | normalizeWhitespace: true, 189 | xmlMode: true 190 | } 191 | } 192 | ``` 193 | These parsing options are taken directly from [htmlparser2](https://github.com/fb55/htmlparser2/wiki/Parser-options), therefore any options that can be used in `htmlparser2` are valid in cheerio as well. The default options are: 194 | 195 | ```js 196 | { 197 | normalizeWhitespace: false, 198 | xmlMode: false, 199 | decodeEntities: true 200 | } 201 | ``` 202 | 203 | For a full list of options and their effects, see [this](https://github.com/fb55/DomHandler) and 204 | [htmlparser2's options](https://github.com/fb55/htmlparser2/wiki/Parser-options). 205 | [source](https://github.com/cheeriojs/cheerio#loading) 206 | 207 | ###Working with JSDOM 208 | 209 | In order to work with JSDOM you will have to install it in your project folder `npm install jsdom`, deal with [compiling C++](https://github.com/tmpvar/jsdom#contextify) and pass it to crawler. 210 | ```javascript 211 | var jsdom = require('jsdom'); 212 | var Crawler = require('node-webcrawler'); 213 | 214 | var c = new Crawler({ 215 | jQuery: jsdom 216 | }); 217 | ``` 218 | 219 | How to test 220 | ----------- 221 | 222 | ### Install and run Httpbin 223 | 224 | node-webcrawler use a local httpbin for testing purpose. You can install httpbin as a library from PyPI and run it as a WSGI app. For example, using Gunicorn: 225 | 226 | $ pip install httpbin 227 | // launch httpbin as a daemon with 6 worker on localhost 228 | $ gunicorn httpbin:app -b 127.0.0.1:8000 -w 6 --daemon 229 | 230 | // Finally 231 | $ npm install && npm test 232 | 233 | ### Alternative: Docker 234 | 235 | After [installing Docker](http://docs.docker.com/), you can run: 236 | 237 | // Builds the local test environment 238 | $ docker build -t node-webcrawler . 239 | 240 | // Runs tests 241 | $ docker run node-webcrawler sh -c "gunicorn httpbin:app -b 127.0.0.1:8000 -w 6 --daemon && npm install && npm test" 242 | 243 | // You can also ssh into the container for easier debugging 244 | $ docker run -i -t node-webcrawler bash 245 | 246 | 247 | [![build status](https://secure.travis-ci.org/bda-research/node-webcrawler.png)](https://travis-ci.org/bda-research/node-webcrawler) 248 | 249 | Rough todolist 250 | -------------- 251 | 252 | * Using bottleneck to deal with rate limits 253 | * Introducing zombie to deal with page with complex ajax 254 | * Refactoring the code to be more maintenable, it's spaghetti code in there ! 255 | * Proxy feature 256 | * This issue: https://github.com/sylvinus/node-crawler/issues/118 257 | * Make Sizzle tests pass (jsdom bug? https://github.com/tmpvar/jsdom/issues#issue/81) 258 | * More crawling tests 259 | * Document the API more (+ the result object) 260 | * Option to wait for callback to finish before freeing the pool resource (via another callback like next()) 261 | 262 | 263 | ChangeLog 264 | --------- 265 | 266 | See https://github.com/bda-research/node-webcrawler/releases 267 | -------------------------------------------------------------------------------- /lib/crawler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | util = require('util'), 5 | EventEmitter = require('events').EventEmitter, 6 | request = require('request'), 7 | _ = require('lodash'), 8 | cheerio = require('cheerio'), 9 | fs = require('fs'), 10 | Pool = require('generic-pool').Pool, 11 | charsetParser = require('charset-parser'), 12 | Bottleneck = require('bottleneck'), 13 | seenreq = require('seenreq'); 14 | 15 | var logger = null; 16 | // Fallback on iconv-lite if we didn't succeed compiling iconv 17 | // https://github.com/sylvinus/node-crawler/pull/29 18 | var iconv, iconvLite; 19 | try { 20 | iconv = require('iconv').Iconv; 21 | } catch (e) {} 22 | 23 | if (!iconv) { 24 | iconvLite = require('iconv-lite'); 25 | } 26 | 27 | function useCache (options) { 28 | return (options.uri || options.url) && options.cache; 29 | } 30 | 31 | function checkJQueryNaming (options) { 32 | if ('jquery' in options) { 33 | options.jQuery = options.jquery; 34 | delete options.jquery; 35 | } 36 | return options; 37 | } 38 | 39 | function readJqueryUrl (url, callback) { 40 | if (url.match(/^(file\:\/\/|\w+\:|\/)/)) { 41 | fs.readFile(url.replace(/^file\:\/\//,''),'utf-8', function(err,jq) { 42 | callback(err, jq); 43 | }); 44 | } else { 45 | callback(null, url); 46 | } 47 | } 48 | 49 | function Crawler (options) { 50 | var self = this; 51 | self.init(options); 52 | } 53 | // augment the prototype for node events using util.inherits 54 | util.inherits(Crawler, EventEmitter); 55 | 56 | Crawler.prototype.init = function init (options) { 57 | var self = this; 58 | 59 | var defaultOptions = { 60 | autoWindowClose: true, 61 | cache: false, 62 | forceUTF8: false, 63 | gzip: true, 64 | incomingEncoding: null, //TODO remove or optimize 65 | jQuery: true, 66 | maxConnections: 10, 67 | bottleneckConcurrent: 10000, 68 | method: 'GET', 69 | onDrain: false, 70 | priority: 5, 71 | priorityRange: 10, 72 | rateLimits: 0, 73 | referer: false, 74 | retries: 3, 75 | retryTimeout: 10000, 76 | timeout: 15000, 77 | skipDuplicates: false, 78 | rotateUA: false 79 | }; 80 | 81 | //return defaultOptions with overriden properties from options. 82 | self.options = _.extend(defaultOptions, options); 83 | 84 | // you can use jquery or jQuery 85 | self.options = checkJQueryNaming(self.options); 86 | 87 | if (self.options.rateLimits !== 0 && self.options.maxConnections == 1) { 88 | //self.options.limiter = "default"; 89 | } else { 90 | //self.limiters = null;//self.options.maxConnections = 1; 91 | } 92 | 93 | // Don't make these options persist to individual queries 94 | self.globalOnlyOptions = ['maxConnections', 'priorityRange', 'onDrain']; 95 | 96 | //Setup a worker pool w/ https://github.com/coopernurse/node-pool 97 | self.pool = Pool({ 98 | name : 'crawler', 99 | max : self.options.maxConnections, 100 | min : self.options.minConnections, 101 | log : self.options.debug && self.options.logger && function(){self.options.logger.log(arguments[1],arguments[0]);}, 102 | priorityRange: self.options.priorityRange, 103 | create : function(callback) { 104 | callback(new Object()); 105 | }, 106 | destroy : function() {} 107 | }); 108 | 109 | self.limiters = new Bottleneck.Cluster(self.options.bottleneckConcurrent,self.options.rateLimits); 110 | self.plannedQueueCallsCount = 0; 111 | self.queueItemSize = 0; 112 | 113 | self.cache = {}; 114 | self.seen = new seenreq(); 115 | self.debug = self.options.debug || false; 116 | self.mapEntity = Object.create(null); 117 | self.entityList = ["jar"]; 118 | logger = self.options.logger || console; 119 | 120 | self.on('pool:release', function(options) { 121 | self._release(options); 122 | }); 123 | 124 | self.on("request",function(options){ 125 | if(_.isFunction(self.options.preRequest)){ 126 | self.options.preRequest(options); 127 | } 128 | }); 129 | 130 | self.on('pool:drain', function() { 131 | if (self.options.onDrain) { 132 | self.options.onDrain.call(self, self.pool); 133 | } 134 | }); 135 | }; 136 | 137 | Crawler.prototype._release = function _release (options) { 138 | var self = this; 139 | 140 | self.queueItemSize--; 141 | if (options._poolReference) { 142 | if(self.debug){ 143 | logger.info("Releasing resource, limiter:%s", options.limiter || "default"); 144 | } 145 | self.pool.release(options._poolReference); 146 | } 147 | 148 | // Pool stats are behaving weird - have to implement our own counter 149 | if (self.queueItemSize + self.plannedQueueCallsCount === 0) { 150 | self.emit('pool:drain'); 151 | } 152 | }; 153 | 154 | Crawler.prototype._inject = function _inject (response, options, callback) { 155 | var $; 156 | var self = this; 157 | 158 | if (options.jQuery === 'cheerio' || options.jQuery.name === 'cheerio' || options.jQuery === true) { 159 | var defaultCheerioOptions = { 160 | normalizeWhitespace: false, 161 | xmlMode: false, 162 | decodeEntities: true 163 | }; 164 | var cheerioOptions = options.jQuery.options || defaultCheerioOptions; 165 | $ = cheerio.load(response.body, cheerioOptions); 166 | 167 | callback(null, $); 168 | } 169 | 170 | else if (options.jQuery.jsdom) { 171 | var jsdom = options.jQuery.jsdom; 172 | var scriptLocation = path.resolve(__dirname, '../vendor/jquery-2.1.1.min.js'); 173 | 174 | //Use promises 175 | readJqueryUrl(scriptLocation, function(err, jquery) { 176 | try { 177 | jsdom.env({ 178 | url: options.uri, 179 | html: response.body, 180 | src: [jquery], 181 | done: function (errors, window) { 182 | $ = window.jQuery; 183 | callback(errors, $); 184 | 185 | try { 186 | window.close(); 187 | window = null; 188 | } catch (err) { 189 | logger.error(err); 190 | } 191 | 192 | } 193 | }); 194 | } catch (e) { 195 | options.callback(e); 196 | self.emit('pool:release', options); 197 | } 198 | }); 199 | } 200 | // Jquery is set to false are not set 201 | else { 202 | callback(null); 203 | } 204 | }; 205 | 206 | Crawler.prototype.queue = function queue (options) { 207 | var self = this; 208 | 209 | // Did you get a single object or string? Make it compatible. 210 | options = _.isArray(options) ? options : [options]; 211 | 212 | options = _.flattenDeep(options); 213 | 214 | for(var i = 0; i < options.length; ++i) { 215 | if(_.isNull(options[i]) || _.isUndefined(options[i]) || (!_.isString(options[i]) && !_.isPlainObject(options[i]))) { 216 | if(self.debug) { 217 | logger.warn("Illegal queue option: ", JSON.stringify(options[i])); 218 | } 219 | continue; 220 | } 221 | self._pushToQueue( 222 | _.isString(options[i]) ? {uri: options[i]} : options[i] 223 | ); 224 | } 225 | }; 226 | 227 | Crawler.prototype._pushToQueue = function _pushToQueue (options) { 228 | var self = this; 229 | self.queueItemSize++; 230 | 231 | // you can use jquery or jQuery 232 | options = checkJQueryNaming(options); 233 | 234 | _.defaults(options, self.options); 235 | 236 | // Remove all the global options from our options 237 | // TODO we are doing this for every _pushToQueue, find a way to avoid this 238 | _.each(self.globalOnlyOptions, function(globalOnlyOption) { 239 | delete options[globalOnlyOption]; 240 | }); 241 | 242 | // If duplicate skipping is enabled, avoid queueing entirely for URLs we already crawled 243 | if (options.skipDuplicates && self.seen.exists(options)) { 244 | return self.emit('pool:release', options); 245 | } 246 | 247 | // acquire connection - callback function is called 248 | // once a resource becomes available 249 | // self.pool.acquire( 250 | var acquired = function(error, poolReference) { 251 | options._poolReference = poolReference; 252 | 253 | // this is and operation error 254 | if (error) { 255 | logger.error(error); 256 | options.callback(error);// need release 257 | return self.emit('pool:release',options); 258 | } 259 | 260 | if(self.debug){ 261 | logger.info("Acquired resource, limiter:%s, uri:%s", options.limiter || "default", options.uri); 262 | logger.info("pool queue size:%s, bottleneck '%s' queue size:%s", self.waitingCount, options.limiter||"default", self.limiters.key(options.limiter||"default")._queue.length); 263 | } 264 | 265 | //Static HTML was given, skip request 266 | if (options.html) { 267 | self._onContent(null, options, {body:options.html}); 268 | } else if (typeof options.uri === 'function') { 269 | options.uri(function(uri) { 270 | options.uri = uri; 271 | self._makeCrawlerRequest(options); 272 | }); 273 | } else { 274 | self._makeCrawlerRequest(options); 275 | } 276 | }//, options.priority); 277 | 278 | var acquireWrapped = function(priority,cb){ 279 | if(self.debug){ 280 | logger.info("Called by bottleneck, limiter:%s, uri:%s", options.limiter || "default", options.uri); 281 | } 282 | 283 | return self.pool.acquire(cb,priority); 284 | } 285 | 286 | self.limiters.key(options.limiter||"default").submit(acquireWrapped,options.priority,acquired); 287 | }; 288 | 289 | Crawler.prototype._makeCrawlerRequest = function _makeCrawlerRequest (options) { 290 | var self = this; 291 | //var cacheData = self.cache[self.seen.normalize(options)]; 292 | 293 | // if(useCache(options) && cacheData){ 294 | // if(self.debug){ 295 | // logger.info("using cache."); 296 | // } 297 | 298 | // self._onContent(null, options, cacheData, true); 299 | // return; 300 | // } 301 | 302 | // if (typeof options.rateLimits === 'number' && options.rateLimits !== 0) { 303 | // setTimeout(function() { 304 | // self._buildHttpRequest(options); 305 | // }, options.rateLimits); 306 | // } else { 307 | self._buildHttpRequest(options); 308 | // } 309 | }; 310 | 311 | Crawler.prototype._deleteEntity = function _deleteEntity(options){ 312 | var self = this; 313 | this.entityList.forEach(function(name){ 314 | if(typeof options[name] == "object"){ 315 | self.mapEntity[name] = options[name]; 316 | delete options[name]; 317 | } 318 | }) 319 | } 320 | 321 | Crawler.prototype._attachEntity = function _attachEntity(options){ 322 | var self = this; 323 | return this.entityList.reduce(function(target,name){ 324 | if(typeof self.mapEntity[name] == "object") 325 | target[name] = self.mapEntity[name]; 326 | 327 | return target; 328 | }, options); 329 | } 330 | 331 | 332 | Crawler.prototype._buildHttpRequest = function _buildHTTPRequest (options) { 333 | var self = this; 334 | 335 | if (self.debug) { 336 | logger.info(options.method+' '+options.uri); 337 | if(options.proxy) 338 | logger.info("Use proxy: %s", options.proxy); 339 | } 340 | 341 | // Cloning keeps the opts parameter clean: 342 | // - some versions of "request" apply the second parameter as a 343 | // property called "callback" to the first parameter 344 | // - keeps the query object fresh in case of a retry 345 | // Doing parse/stringify instead of _.clone will do a deep clone and remove functions 346 | 347 | self._deleteEntity(options); 348 | var ropts = JSON.parse(JSON.stringify(options)); 349 | self._attachEntity(ropts); 350 | 351 | if (!ropts.headers) { ropts.headers={}; } 352 | if (ropts.forceUTF8) { 353 | // if (!ropts.headers['Accept-Charset'] && !ropts.headers['accept-charset']) { 354 | // ropts.headers['Accept-Charset'] = 'utf-8;q=0.7,*;q=0.3'; 355 | // } 356 | 357 | ropts.encoding=null; 358 | } 359 | 360 | if (ropts.userAgent) { 361 | if(ropts.rotateUA && _.isArray(ropts.userAgent)){ 362 | ropts.headers['User-Agent'] = ropts.userAgent[0]; 363 | // If "rotateUA" is true, rotate User-Agent 364 | options.userAgent.push(options.userAgent.shift()); 365 | }else{ 366 | ropts.headers['User-Agent'] = ropts.userAgent; 367 | } 368 | if(self.debug){ 369 | logger.info(ropts.headers['User-Agent']); 370 | } 371 | } 372 | if (ropts.referer) { 373 | ropts.headers.Referer = ropts.referer; 374 | } 375 | if (ropts.proxies && ropts.proxies.length) { 376 | ropts.proxy = ropts.proxies[0]; 377 | } 378 | 379 | this.emit("request",ropts); 380 | 381 | var requestArgs = ['uri','url','qs','method','headers','body','form','json','multipart','followRedirect', 382 | 'followAllRedirects', 'maxRedirects','encoding','pool','timeout','proxy','auth','oauth','strictSSL', 383 | 'jar','aws','gzip','time','tunnel','proxyHeaderWhiteList','proxyHeaderExclusiveList','localAddress','forever']; 384 | 385 | var req = request(_.pick.apply(this,[ropts].concat(requestArgs)), function(error,response) { 386 | if (error) { 387 | return self._onContent(error, options); 388 | } 389 | 390 | response.uri = response.request.href; 391 | self._onContent(error,options,response); 392 | }); 393 | }; 394 | 395 | Crawler.prototype._onContent = function _onContent (error, options, response, fromCache) { 396 | var self = this; 397 | 398 | if (error) { 399 | if (self.debug) { 400 | logger.error('Error '+error+' when fetching '+ 401 | options.uri+(options.retries?' ('+options.retries+' retries left)':'')); 402 | } 403 | if (options.retries) { 404 | self.plannedQueueCallsCount++; 405 | setTimeout(function() { 406 | options.retries--; 407 | self.plannedQueueCallsCount--; 408 | 409 | // If there is a "proxies" option, rotate it so that we don't keep hitting the same one 410 | // if (options.proxies) { 411 | // options.proxies.push(options.proxies.shift()); 412 | // } 413 | self.queue(options); 414 | },options.retryTimeout); 415 | 416 | } else if (options.callback) { 417 | options.callback(error,{options:options}); 418 | } 419 | 420 | return self.emit('pool:release', options); 421 | } 422 | 423 | if (!response.body) { response.body=''; } 424 | 425 | if (self.debug) { 426 | logger.info('Got '+(options.uri||'html')+' ('+response.body.length+' bytes)...'); 427 | } 428 | 429 | if(!fromCache){ 430 | try{ 431 | self._doEncoding(options,response); 432 | }catch(e){ 433 | logger.error(e); 434 | if(options.callback){ 435 | options.callback(e); 436 | } 437 | return self.emit('pool:release',options); 438 | } 439 | } 440 | 441 | // if(useCache(options)){ 442 | // self.cache[self.seen.normalize(options)] = response; 443 | // } 444 | 445 | if (!options.callback) { 446 | return self.emit('pool:release', options); 447 | } 448 | 449 | response.options = options; 450 | 451 | // This could definitely be improved by *also* matching content-type headers 452 | var isHTML = _.isString(response.body) && response.body.match(/^\s*

hello

dude

', 114 | callback : function(error, response) { 115 | expect(error).to.be.null; 116 | expect(response).not.to.be.null; 117 | done(); 118 | } 119 | }); 120 | }); 121 | it('should not return an error on a malformed html if jQuery is jsdom', function(done) { 122 | c.queue({ 123 | html : '

hello

dude

', 124 | jQuery : jsdom, 125 | callback : function(error, response) { 126 | expect(error).to.be.null; 127 | expect(response).not.to.be.undefined; 128 | done(); 129 | } 130 | }); 131 | }); 132 | }); 133 | }); 134 | -------------------------------------------------------------------------------- /tests/examples.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Crawler = require('../lib/crawler'); 4 | var expect = require('chai').expect; 5 | var httpbinHost = 'localhost:8000'; 6 | var sinon = require('sinon'); 7 | var url = require('url'); 8 | var c, spy; 9 | 10 | describe('Simple test', function() { 11 | afterEach(function() { 12 | c = {}; 13 | spy = {}; 14 | }); 15 | it('should run the first readme examples', function(done) { 16 | c = new Crawler({ 17 | maxConnections: 10, 18 | onDrain: function() { 19 | done(); 20 | }, 21 | callback: function(error, result) { 22 | expect(typeof result.body).to.equal('string'); 23 | } 24 | }); 25 | c.queue('http://google.com'); 26 | }); 27 | it('should run the readme examples', function(done) { 28 | c = new Crawler({ 29 | maxConnections: 10, 30 | onDrain: function() { 31 | expect(spy.calledTwice).to.be.true; 32 | done(); 33 | }, 34 | callback: function(error, result, $) { 35 | var baseUrl = result.uri; 36 | $('a').each(function(index, a) { 37 | var toQueueUrl = url.resolve(baseUrl, $(a).attr('href')); 38 | c.queue(toQueueUrl); 39 | }); 40 | } 41 | }); 42 | spy = sinon.spy(c, 'queue'); 43 | c.queue('http://'+httpbinHost+'/links/1/1'); 44 | }); 45 | it('should run the with an array queue', function(done) { 46 | c = new Crawler(); 47 | c.queue([{ 48 | uri: 'http://www.google.com', 49 | jquery: true, 50 | callback : function(error, result, $) //noinspection BadExpressionStatementJS,BadExpressionStatementJS 51 | { 52 | expect($).not.to.be.null; 53 | expect(typeof result.body).to.equal('string'); 54 | done(); 55 | } 56 | }]); 57 | }); 58 | }); -------------------------------------------------------------------------------- /tests/jqueryOption.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Crawler = require('../lib/crawler'); 4 | var expect = require('chai').expect; 5 | var given = require('mocha-testdata'); 6 | var path = require('path'); 7 | var jsdom = require('jsdom'); 8 | 9 | var httpbinHost = 'localhost:8000'; 10 | var c; 11 | 12 | describe('Jquery testing', function() { 13 | afterEach(function() { 14 | c = {}; 15 | }); 16 | describe('Jquery parsing', function() { 17 | given.async(jsdom, 'cheerio') 18 | .it('should work on inline html', function(done, jquery) { 19 | c = new Crawler(); 20 | c.queue([{ 21 | html: '

great!

', 22 | jquery: jquery, 23 | callback: function(error, result, $) //noinspection BadExpressionStatementJS,BadExpressionStatementJS 24 | { 25 | expect(error).to.be.null; 26 | expect($('i').html()).to.equal('great!'); 27 | done(); 28 | } 29 | }]); 30 | }); 31 | }); 32 | describe('Jquery injection', function() { 33 | it('should enable cheerio by default', function(done) { 34 | c = new Crawler({ 35 | callback:function(error, result, $) { 36 | expect(error).to.be.null; 37 | expect(typeof $).to.equal('function'); 38 | expect(typeof $.root).to.equal('function'); 39 | done(); 40 | } 41 | }); 42 | c.queue(['http://'+httpbinHost+'/']); 43 | }); 44 | given.async(jsdom).it('should enable jsdom if set', function(done, jquery) { 45 | c = new Crawler({ 46 | jquery: jquery, 47 | callback:function(error, result, $) { 48 | expect(error).to.be.null; 49 | expect($.fn.jquery).to.equal('2.1.1'); 50 | done(); 51 | } 52 | }); 53 | c.queue(['http://'+httpbinHost+'/']); 54 | }); 55 | given.async('cheerio', {name: 'cheerio'}).it('should enable cheerio if set', function(done, jquery) { 56 | c = new Crawler({ 57 | jquery: jquery, 58 | callback:function(error, result, $) { 59 | expect(error).to.be.null; 60 | expect(typeof $).to.equal('function'); 61 | expect(typeof $.root).to.equal('function'); 62 | done(); 63 | } 64 | }); 65 | c.queue(['http://'+httpbinHost+'/']); 66 | }); 67 | it('should disable jQuery if set to false', function(done) { 68 | c = new Crawler({ 69 | jQuery: false, 70 | callback:function(error, result, $) { 71 | expect(error).to.be.null; 72 | expect($).to.be.undefined; 73 | done(); 74 | } 75 | }); 76 | c.queue(['http://'+httpbinHost+'/']); 77 | }); 78 | given.async('trucmuch', null, undefined).it('should not inject jquery', function(done, jquery) { 79 | c = new Crawler({ 80 | jquery: jquery, 81 | callback:function(error, result, $) { 82 | expect(error).to.be.null; 83 | expect($).to.be.undefined; 84 | done(); 85 | } 86 | }); 87 | c.queue(['http://'+httpbinHost+'/']); 88 | }); 89 | given.async('cheerio', jsdom).it('should auto-disable jQuery if no html tag first', function(done, jquery) { 90 | c = new Crawler({ 91 | jQuery: jquery, 92 | callback:function(error, result, $) { 93 | expect(error).to.be.null; 94 | expect($).to.be.undefined; 95 | done(); 96 | } 97 | }); 98 | c.queue(['http://'+httpbinHost+'/status/200']); 99 | }); 100 | it('should work if jquery is set instead of jQuery when building Crawler', function(done) { 101 | c = new Crawler({ 102 | maxConnections: 10, 103 | jquery: true, 104 | onDrain: function() { 105 | done(); 106 | }, 107 | callback: function(error, result, $) { 108 | expect($).not.to.be.undefined; 109 | expect(result.options.jQuery).to.be.true; 110 | expect(result.options.jquery).to.be.undefined; 111 | } 112 | }); 113 | c.queue(['http://'+httpbinHost]); 114 | }); 115 | it('should work if jquery is set instead of jQuery when queuing', function(done) { 116 | c = new Crawler({ 117 | maxConnections: 10, 118 | jQuery: true, 119 | onDrain: function() { 120 | done(); 121 | }, 122 | callback: function(error, result, $) { 123 | expect($).to.be.undefined; 124 | expect(result.options.jQuery).to.be.false; 125 | } 126 | }); 127 | c.queue([ 128 | { 129 | uri: 'http://'+httpbinHost, 130 | jquery : false 131 | } 132 | ]); 133 | }); 134 | it('should not inject jquery if jquery is set to undefined', function(done) { 135 | c = new Crawler({ 136 | maxConnections: 10, 137 | jquery: undefined, 138 | onDrain: function() { 139 | done(); 140 | }, 141 | callback: function(error, result, $) { 142 | expect($).to.be.undefined; 143 | expect(result.options.jQuery).to.be.undefined; 144 | } 145 | }); 146 | c.queue(['http://'+httpbinHost]); 147 | }); 148 | }); 149 | describe('Cheerio specific test', function() { 150 | it('should inject cheerio with options', function(done) { 151 | var cheerioConf = { 152 | name: 'cheerio', 153 | options: { 154 | normalizeWhitespace: true, 155 | xmlMode: true 156 | } 157 | }; 158 | c = new Crawler({ 159 | maxConnections: 10, 160 | jquery: cheerioConf, 161 | onDrain: function() { 162 | done(); 163 | }, 164 | callback: function(error, result, $) { 165 | expect($._options.normalizeWhitespace).to.be.true; 166 | expect($._options.xmlMode).to.be.true; 167 | // check if the default value of decodeEntities is still true 168 | expect($._options.decodeEntities).to.be.true; 169 | } 170 | }); 171 | c.queue(['http://'+httpbinHost]); 172 | }); 173 | }); 174 | }); 175 | -------------------------------------------------------------------------------- /tests/linksResolving.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Crawler = require('../lib/crawler'); 4 | var expect = require('chai').expect; 5 | var _ = require('lodash'); 6 | var jsdom = require('jsdom'); 7 | var httpbinHost = 'localhost:8000'; 8 | var c; 9 | 10 | describe('Links', function() { 11 | beforeEach(function() { 12 | c = new Crawler({ 13 | forceUTF8: true, 14 | jquery: jsdom 15 | }); 16 | }); 17 | it('should resolved links to absolute urls with jsdom', function(done) { 18 | c.queue([{ 19 | uri : 'http://'+httpbinHost+'/links/3/0', 20 | callback: function(error, result, $) //noinspection BadExpressionStatementJS,BadExpressionStatementJS 21 | { 22 | 23 | var links = _.map($('a'), function(a) { 24 | return a.href; 25 | }); 26 | //Both links should be resolve to absolute URLs 27 | expect(links[0]).to.equal('http://'+httpbinHost+'/links/3/1'); 28 | expect(links[1]).to.equal('http://'+httpbinHost+'/links/3/2'); 29 | expect(error).to.be.null; 30 | done(); 31 | } 32 | }]); 33 | }); 34 | it('should resolved links to absolute urls after redirect with jsdom', function(done) { 35 | c.queue([{ 36 | uri : 'http://'+httpbinHost+'/redirect-to?url=http://example.com/', 37 | callback: function(error, result) { 38 | 39 | expect(result.uri).to.equal('http://example.com/'); 40 | expect(error).to.be.null; 41 | done(); 42 | } 43 | }]); 44 | }); 45 | }); -------------------------------------------------------------------------------- /tests/memoryLeaks.test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | // 3 | // var Crawler = require('../../lib/crawler').Crawler; 4 | //var expect = require('chai').expect; 5 | //var _ = require('underscore'); 6 | //var memwatch = require('memwatch'); 7 | //var httpbinHost = 'localhost:8000'; 8 | // 9 | //var c; 10 | // 11 | //describe('Leaks', function() { 12 | // afterEach(function(){ 13 | // c = {}; 14 | // }); 15 | // it('should leak with JSDOM enabled and without autoWindowClose', function(done){ 16 | // 17 | // //disabled mocha timeout for this particular test 18 | // this.timeout(999999999); 19 | // 20 | // var N = 100; 21 | // var hd; 22 | // c = new Crawler({ 23 | // jQuery: true, 24 | // timeout: 500, 25 | // autoWindowClose: false, 26 | // retryTimeout: 1000, 27 | // retries: 1, 28 | // onDrain: function() { 29 | // // Wait a bit for the GC to kick in 30 | // setTimeout(function() { 31 | // var diff = hd.end(); 32 | // //Should have grown by more than 2 MB. 33 | // expect(diff.change.size_bytes).to.be.above(2000000); 34 | // done(); 35 | // }, 10000); 36 | // } 37 | // }); 38 | // 39 | // hd = new memwatch.HeapDiff(); 40 | // for (var i=0; ia?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+Math.random()}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b) 3 | },_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("