├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── after-install.sh ├── before-remove.sh ├── build-urepo-uploader.sh ├── etc ├── logrotate.d │ └── urepo ├── skel │ └── .urepo-upload.sh.conf └── urepo │ ├── urepo-config.sh │ ├── urepo-nginx │ └── urepo.conf.example ├── extract-post-file.c ├── test ├── 001-1kb-test │ ├── files │ │ └── 1kb.random │ ├── stderr │ ├── stdin │ └── stdout ├── 002-empty-test │ ├── files │ │ └── empty │ ├── stderr │ ├── stdin │ └── stdout ├── 003-text-test │ ├── files │ │ └── text.txt │ ├── stderr │ ├── stdin │ └── stdout ├── 004-1kb-text-test │ ├── files │ │ ├── 1kb.random │ │ └── empty │ ├── stderr │ ├── stdin │ └── stdout ├── 005-text-1kb-test │ ├── files │ │ ├── 1kb.random │ │ └── empty │ ├── stderr │ ├── stdin │ └── stdout ├── 006-field-1kb-text │ ├── files │ │ └── 1kb.random │ ├── stderr │ ├── stdin │ └── stdout ├── 007-1kb-field-test │ ├── files │ │ └── 1kb.random │ ├── stderr │ ├── stdin │ └── stdout ├── 008-field-1kb-field-test │ ├── files │ │ └── 1kb.random │ ├── stderr │ ├── stdin │ └── stdout ├── 009-1kb-field-text-test │ ├── files │ │ ├── 1kb.random │ │ └── text.txt │ ├── stderr │ ├── stdin │ └── stdout ├── 010-field-1kb-field-text-field-test │ ├── files │ │ ├── 1kb.random │ │ └── text.txt │ ├── stderr │ ├── stdin │ └── stdout └── run-test.sh ├── usr └── bin │ └── urepo-upload.sh └── var └── urepo ├── cgi ├── process-file └── urepo-functions ├── favicon.ico ├── index.html └── jquery.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | .*sw? 2 | *.deb 3 | *.rpm 4 | build 5 | extract-post-file 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 by Hulu, LLC 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. 8 | 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PKG_NAME=urepo 2 | PKG_VERSION=2.2.6 3 | PKG_DESCRIPTION="Universal repository for Linux binary packages" 4 | PKG_URL=https://github.com/hulu/urepo 5 | PKG_LICENSE="MIT License" 6 | PKG_VENDOR="Hulu" 7 | PKG_MAINTAINER="infra-eng@hulu.com" 8 | 9 | .PHONY: all 10 | SHELL=/bin/bash 11 | 12 | all: pkg 13 | 14 | bin: 15 | gcc -Wall -O2 -o extract-post-file extract-post-file.c 16 | 17 | test: bin 18 | test/run-test.sh 19 | 20 | clean: 21 | rm -rf extract-post-file build_${PKG_VERSION} 22 | 23 | pkg: bin 24 | mkdir build_${PKG_VERSION} 25 | cp -r {var,etc} build_${PKG_VERSION}/ 26 | cp extract-post-file build_${PKG_VERSION}/var/urepo/cgi 27 | cd build_${PKG_VERSION} && \ 28 | fpm --deb-user root --deb-group root \ 29 | -d nginx -d fcgiwrap -d createrepo \ 30 | --deb-no-default-config-files \ 31 | --description $(PKG_DESCRIPTION) \ 32 | --license $(PKG_LICENSE) \ 33 | --vendor $(PKG_VENDOR) \ 34 | --maintainer $(PKG_MAINTAINER) \ 35 | --url $(PKG_URL) \ 36 | --after-install ../after-install.sh \ 37 | --before-remove ../before-remove.sh \ 38 | -s dir -t deb -v $(PKG_VERSION) -n $(PKG_NAME) `find . -type f` && \ 39 | find . ! -name '*.deb' -delete 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | urepo: universal repository for linux binary packages 2 | ======================================= 3 | 4 | Urepo can host both rpm and deb packages. Nginx is used as a web frontend. 5 | Generation of metadata is done by apt-ftparchive for .deb packages and by 6 | createrepo for .rpm packages. File upload can be done using pure HTTP via 7 | browser by using http://urepo.server/ URL or from command line: 8 | 9 | ``` 10 | curl -X POST -s -F dist=centos7 \ 11 | -F branch=stable \ 12 | -F file1=@/path/to/pkg.rpm \ 13 | http://urepo.server/cgi/process-file 14 | ``` 15 | 16 | The process-file hook invokes the appropriate handler according to package file extension. 17 | 18 | Another way to upload a package is to use the urepo-upload.sh utility. It uses 19 | SSH for uploading, after upload is done it triggers file processing via the 20 | same http://urepo.server/cgi/process-file hook. 21 | 22 | In order to delete package DELETE request can be used: 23 | 24 | ``` 25 | curl -X DELETE -s -F dist=centos7 \ 26 | -F branch=stable \ 27 | -F file1=pkg.rpm \ 28 | http://urepo.server/cgi/process-file 29 | ``` 30 | 31 | Drawbacks of current system: 32 | - no support for uploading only signed packages 33 | - no authentication for deleting packages 34 | - in order to promote package from testing to stable you need to reupload 35 | it, should use hard link instead 36 | - due to immediate processing single instance of processing code can run 37 | at a time, this can become bottleneck if uploading would happen often 38 | 39 | ## Building urepo 40 | 41 | Currently urepo can be installed **only** on Ubuntu or other Debian derivatives. 42 | 43 | ### Requirements 44 | 45 | #### Package management requirements 46 | 47 | First you'll need to install a few packages to correctly build: 48 | 49 | ``` 50 | apt install git build-essential nginx fcgiwrap createrepo 51 | ``` 52 | 53 | #### Install FPM 54 | 55 | Urepo requires fpm to run correctly, please follow the installation [instructions](https://fpm.readthedocs.io/en/latest/installation.html) before proceeding. 56 | 57 | ### Download urepo 58 | 59 | Time to download urepo, follow these steps: 60 | 61 | ``` 62 | cd 63 | git clone https://github.com/hulu/urepo.git 64 | cd urepo 65 | ``` 66 | 67 | ### Pre-configuration 68 | 69 | Now we'll pre-configure your urepo before building the package; open **etc/urepo/urepo.conf**, where you can define: 70 | + DEB 71 | + **DEB_CODENAMES**: [Debian](https://en.wikipedia.org/wiki/Debian_version_history)/[Ubuntu](https://en.wikipedia.org/wiki/Ubuntu_(operating_system)#Releases) releases; it can be jessie, stretch, etc ... 72 | + **DEB_ARCHITECTURES**: default binary [architectures](https://wiki.debian.org/SupportedArchitectures) to support; it can be amd64, i386, etc. 73 | + **DEB_COMPONENTS**: tweaks of the release; it can be stable, testing, etc. 74 | * **DEB_CUSTOM_ARCHES**: _optional_ extra architectures to support for specific release(s); not required, should be formatted as a bash dictionary, e.g. `declare -A DEB_CUSTOM_ARCHES=([focal]="arm64")` 75 | 76 | + RPM 77 | + **RPM_RELEASES**: [CentOS](https://en.wikipedia.org/wiki/CentOS#Versioning_and_releases) releases; it can be centos7, rocky8, etc ... 78 | * **RPM_ARCHITECTURES**: default binary [architectures](https://fedoraproject.org/wiki/Architectures) to support; it can be x86\_64, aarch64, etc. 79 | + **RPM_COMPONENTS**: tweaks of the release; it can be stable, testing, etc. 80 | * **RPM_CUSTOM_ARCHES**: _optional_ extra architectures to support for specific release(s); not required, should be formatted as a bash dictionary, e.g. `declare -A RPM_CUSTOM_ARCHES=([rocky8]="aarch64")` 81 | 82 | It's important that you correctly configure this part before the build since the building part will configure the upload page and also the main configuration file **/etc/urepo/urepo.conf**. 83 | 84 | We don't cover other parameters since they are more easy to change, for example **UREPO_ROOT** which is the root directory to keep your .deb and .rpm files. 85 | 86 | ### Let's make 87 | 88 | Now you can build your urepo binary as follow: 89 | 90 | ``` 91 | make pkg 92 | ``` 93 | 94 | If all goes well, it should tell you something like this: 95 | 96 | ``` 97 | gcc -Wall -O2 -o extract-post-file extract-post-file.c 98 | mkdir build_2.2.6 99 | cp -r {var,etc} build_2.2.6/ 100 | cp extract-post-file build_2.2.6/var/urepo/cgi 101 | cd build_2.2.6 && \ 102 | fpm --deb-user root --deb-group root \ 103 | -d nginx -d fcgiwrap -d createrepo \ 104 | --deb-no-default-config-files \ 105 | --description "Universal repository for Linux binary packages" \ 106 | --license "MIT License" \ 107 | --vendor "Hulu" \ 108 | --maintainer "infra-eng@hulu.com" \ 109 | --url https://github.com/hulu/urepo \ 110 | --after-install ../after-install.sh \ 111 | --before-remove ../before-remove.sh \ 112 | -s dir -t deb -v 2.2.6 -n urepo `find . -type f` && \ 113 | find . ! -name '*.deb' -delete 114 | Created package {:path=>"urepo_2.2.6_amd64.deb"} 115 | ``` 116 | 117 | If you get the following error message: 118 | 119 | ``` 120 | gcc -Wall -O2 -o extract-post-file extract-post-file.c 121 | mkdir build 122 | mkdir: impossible de créer le répertoire « build »: Le fichier existe 123 | makefile:14 : la recette pour la cible « pkg » a échouée 124 | make: *** [pkg] Erreur 1 125 | ``` 126 | 127 | you may have tried to build before installing all the requirements, so clean the mess: 128 | 129 | ``` 130 | make clean 131 | ``` 132 | 133 | Check the requirements above and try again. 134 | 135 | ### Install urepo.deb 136 | 137 | When you have built the urepo.deb package, you can install it: 138 | 139 | ``` 140 | cd build/ 141 | dpkg -i urepo_x.y.z_amd64.deb 142 | ``` 143 | 144 | ### Check 145 | 146 | Now that it's installed, you can check that it's running. Open up **/etc/nginx/sites-enabled/urepo-nginx** and open the **server_name** in your brower, if you see an upload form, then it worked! 147 | 148 | ## Building urepo-upload 149 | 150 | Urepo-upload is build by running build-urepo-upload.sh, which creates both .deb and .rpm packages. 151 | 152 | ## Add your urepo server to your package manager 153 | 154 | ### Debian/Ubuntu 155 | 156 | Do as follows: 157 | 158 | ``` 159 | echo 'deb [trusted=yes] http://myurepo.server/deb {DEB_CODENAMES} {DEB_COMPONENTS}' > /etc/apt/sources.list.d/myurepo.list 160 | ``` 161 | 162 | Now you can update and list the packages from your own urepo server: 163 | 164 | ``` 165 | apt update 166 | apt list mypackage 167 | ``` 168 | 169 | ### CentOS/RedHat 170 | 171 | Do as follows where, e.g., DISTRO = "centos7", BRANCH = "testing", ARCHITECTURE = "x86\_64": 172 | 173 | ``` 174 | cat < /etc/yum.repos.d/myurepo.list 175 | [myurepo] 176 | name=myurepo 177 | enabled=1 178 | baseurl=http://myurepo.server/rpm/${DISTRO}/${BRANCH}/${ARCHITECTURE} 179 | gpgcheck=0 180 | EOF 181 | ``` 182 | 183 | This should now make it possible to search your own urepo server: 184 | 185 | ``` 186 | yum search mypackage 187 | ``` 188 | 189 | ## Known issues / Common mistakes 190 | 191 | ### Wrong component 192 | 193 | ``` 194 | W: Failed to fetch https://urepo.server/deb/dists/jessie/Release: Unable to find expected entry 'main/binary-amd64/Packages' in Release file (Wrong sources.list entry or malformed file) 195 | E: Some index files failed to download. They have been ignored, or old ones used instead. 196 | ``` 197 | 198 | Please check that the **DEB_COMPONENTS** is the same in your sources.list and in your urepo.conf, there it's **main** but maybe urepo is not configured to work with it. 199 | -------------------------------------------------------------------------------- /after-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [ -f /etc/urepo/urepo.conf ] || cp /etc/urepo/urepo.conf.example /etc/urepo/urepo.conf 4 | /etc/urepo/urepo-config.sh 5 | -------------------------------------------------------------------------------- /before-remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | deb_remove() { 4 | rm -f /etc/nginx/sites-enabled/repo-nginx 5 | /etc/init.d/nginx restart 6 | } 7 | 8 | deb_upgrade() { 9 | return 0 10 | } 11 | 12 | case ${1:-} in 13 | remove|purge) deb_remove ;; 14 | upgrade) deb_upgrade ;; 15 | esac 16 | -------------------------------------------------------------------------------- /build-urepo-uploader.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PKG_VERSION="2.0.0" 4 | PKG_NAME="urepo-upload" 5 | 6 | PKG_DESCRIPTION="Uploading tool for urepo (universal repository for linux binary packages)" 7 | 8 | fpm --deb-user root --deb-group root \ 9 | --description "${PKG_DESCRIPTION}" \ 10 | -a all -s dir -t deb -v ${PKG_VERSION} -n ${PKG_NAME} $(find {usr/bin,etc/skel} -type f) 11 | 12 | fpm --rpm-user root --rpm-group root \ 13 | --description "${PKG_DESCRIPTION}" \ 14 | -a all -s dir -t rpm -v ${PKG_VERSION} -n ${PKG_NAME} $(find {usr/bin,etc/skel} -type f) 15 | 16 | -------------------------------------------------------------------------------- /etc/logrotate.d/urepo: -------------------------------------------------------------------------------- 1 | /var/log/urepo.log 2 | { 3 | rotate 10 4 | daily 5 | size 100k 6 | missingok 7 | notifempty 8 | compress 9 | delaycompress 10 | } 11 | 12 | -------------------------------------------------------------------------------- /etc/skel/.urepo-upload.sh.conf: -------------------------------------------------------------------------------- 1 | UREPO_SERVER=pkg.prod.hulu.com 2 | UREPO_UPLOAD_DIR=/var/urepo/upload 3 | -------------------------------------------------------------------------------- /etc/urepo/urepo-config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -u 4 | 5 | # let's load urepo config file ... 6 | . /etc/urepo/urepo.conf 7 | # ... and functions 8 | . $UREPO_ROOT/cgi/urepo-functions 9 | # this variable would contain json for the page, showing upload form 10 | # json would contain entries like: release_name: [branch_name1, branch_name2, ...] 11 | data="" 12 | # let's create rpm directory hierarchy 13 | mkdir -p $RPM_REPO_ROOT && chmod -R +r $RPM_REPO_ROOT 14 | for release in $RPM_RELEASES; do 15 | options="" 16 | for component in $RPM_COMPONENTS; do 17 | options+="${options:+, }\"$component\"" 18 | for arch in $RPM_ARCHITECTURES; do 19 | dir="$RPM_REPO_ROOT/$release/$component/$arch" 20 | mkdir -p "$dir" 21 | createrepo -s sha -q -c $dir/.cache $dir 22 | done 23 | # let's handle non-default architectures 24 | if [ -v RPM_CUSTOM_ARCHES[@] ] && [ -v RPM_CUSTOM_ARCHES[$release] ]; then 25 | for arch in ${RPM_CUSTOM_ARCHES[$release]}; do 26 | dir="$RPM_REPO_ROOT/$release/$component/$arch" 27 | mkdir -p "$dir" 28 | createrepo -s sha -q -c $dir/.cache $dir 29 | done 30 | fi 31 | done 32 | data+="${data:+, }$release: [$options]" 33 | done 34 | # let's create deb directory hierarchy 35 | mkdir -p $DEB_REPO_ROOT && cd $DEB_REPO_ROOT && chmod -R +r . 36 | for dist in $DEB_CODENAMES; do 37 | options="" 38 | for branch in $DEB_COMPONENTS; do 39 | options+="${options:+, }\"$branch\"" 40 | pool_dir=pool/$dist/$branch 41 | mkdir -p $pool_dir 42 | for arch in $DEB_ARCHITECTURES; do 43 | mkdir -p dists/$dist/$branch/binary-$arch 44 | done 45 | # let's handle non-default architectures 46 | if [ -v DEB_CUSTOM_ARCHES[@] ] && [ -v DEB_CUSTOM_ARCHES[$dist] ]; then 47 | for arch in ${DEB_CUSTOM_ARCHES[$dist]}; do 48 | mkdir -p dists/$dist/$branch/binary-$arch 49 | done 50 | fi 51 | ( generate_repo_data ) 52 | done 53 | data+=", $dist: [$options]" 54 | done 55 | # let's create directory where files would be uploaded 56 | mkdir -p $UREPO_UPLOAD_DIR 57 | # this directory should be writeable by everybody (for ssh uploads) 58 | # but readable only by owner for security 59 | # security is rather weak, if one user would know name of the file other 60 | # user is uploading he still would be able to change content of this file 61 | # since urepo is not working as root not much can be done here 62 | chmod 0733 $UREPO_UPLOAD_DIR 63 | # let's update file ownership according to user we are working as 64 | chown -R www-data:www-data $UREPO_ROOT 65 | mkdir -p $(dirname $UREPO_LOG) 66 | chown -R www-data:www-data $(dirname $UREPO_LOG) 67 | # now let's set hostname in nginx config 68 | host_name=$(hostname -f) 69 | sed -i -e "s/server_name[^;]*;/server_name ${host_name};/" /etc/urepo/urepo-nginx 70 | # and insert json for upload form generation 71 | sed -i -e "s/\(var data = {\).*\(};\)/\1$data\2/" $UREPO_ROOT/index.html 72 | # let's enable urepo nginx config 73 | rm -f /etc/nginx/sites-enabled/default 74 | ln -nsf /etc/urepo/urepo-nginx /etc/nginx/sites-enabled/urepo-nginx 75 | # and restart nginx 76 | /etc/init.d/nginx restart 77 | -------------------------------------------------------------------------------- /etc/urepo/urepo-nginx: -------------------------------------------------------------------------------- 1 | server { 2 | client_max_body_size 512m; 3 | root /var/urepo; 4 | index index.html; 5 | server_name localhost; 6 | 7 | location / { 8 | autoindex on; 9 | } 10 | 11 | location ~ ^/cgi { 12 | root /var/urepo/cgi; 13 | rewrite ^/cgi/(.*) /$1 break; 14 | 15 | include fastcgi_params; 16 | fastcgi_pass unix:/var/run/fcgiwrap.socket; 17 | fastcgi_param SCRIPT_FILENAME /var/urepo/cgi$fastcgi_script_name; 18 | fastcgi_read_timeout 300; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /etc/urepo/urepo.conf.example: -------------------------------------------------------------------------------- 1 | UREPO_ROOT=/var/urepo 2 | UREPO_UPLOAD_DIR=$UREPO_ROOT/upload 3 | UREPO_LOG=/var/log/urepo/urepo.log 4 | 5 | DEB_REPO_ROOT=/var/urepo/deb 6 | DEB_CODENAMES="bionic focal jammy" 7 | DEB_ARCHITECTURES="amd64" 8 | DEB_COMPONENTS="stable testing" 9 | declare -A DEB_CUSTOM_ARCHES=( 10 | [focal]="arm64" 11 | ) 12 | 13 | RPM_REPO_ROOT=/var/urepo/rpm 14 | RPM_RELEASES="centos7 rocky8 rocky9" 15 | RPM_ARCHITECTURES="x86_64 SRPMS" 16 | RPM_COMPONENTS="stable testing" 17 | declare -A RPM_CUSTOM_ARCHES=( 18 | [centos7]="aarch64" 19 | ) 20 | 21 | -------------------------------------------------------------------------------- /extract-post-file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This utility was created because nginx 1.3.9+ doesn't have http upload module any more. 3 | * This utility accepts post request on stdin and saves in current directory files 4 | * from request if any. File data is removed from post request, rest part of post request 5 | * is piped through unchanged. 6 | * 7 | * Author: kirill.timofeev@hulu.com 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | // constants for state machine 19 | #define STATE_NONE 0 20 | #define STATE_BOUNDARY_FOUND 1 21 | #define STATE_FILE_OPENED 2 22 | #define STATE_CONTENT_TYPE_FOUND 3 23 | #define STATE_EMPTY_LINE_FOUND 4 24 | #define STATE_WRITE_TO_FILE 5 25 | 26 | // strlen definition that can be used with defined strings 27 | #define STRLEN(s) (sizeof(s) / sizeof(s[0]) - 1) 28 | 29 | // strings we want to recognise in the input stream 30 | #define CONTENT_DISPOSITION_STR "Content-Disposition: form-data; " 31 | #define CONTENT_TYPE_STR "Content-Type:" 32 | #define EMPTY_LINE_STR "\r\n" 33 | #define FILENAME_STR "filename=\"" 34 | 35 | #define CONTENT_DISPOSITION_LEN STRLEN(CONTENT_DISPOSITION_STR) 36 | #define CONTENT_TYPE_LEN STRLEN(CONTENT_TYPE_STR) 37 | #define EMPTY_LINE_LEN STRLEN(EMPTY_LINE_STR) 38 | #define FILENAME_LEN STRLEN(FILENAME_STR) 39 | 40 | // boundary string is stored in separate buffer 41 | // this is 1st line of the input stream 42 | #define BOUNDARY_BUF_SIZE 128 43 | char boundary_buf[BOUNDARY_BUF_SIZE]; 44 | int boundary_len = 0; 45 | 46 | // buffer used while reading rest of input stream 47 | #define DATA_BUF_SIZE 8192 48 | 49 | // perl like die() function 50 | void die(const char * format, ...) { 51 | va_list vargs; 52 | 53 | va_start(vargs, format); 54 | vfprintf(stderr, format, vargs); 55 | exit(1); 56 | } 57 | 58 | // This function processes Content-Disposition string 59 | // It tries to locate filename, strips path if any and openes 60 | // file in exclusive write mode in current directory. 61 | // Returns FILE * in case of success, NULL if Content-Disposition 62 | // string has no filename 63 | FILE *open_file(char *buf, int *length) { 64 | char *file_name = NULL; // pointer to filename 65 | char *file_name_eos = NULL; // pointer to end of string with filename 66 | char *c = NULL; // temporary pointer 67 | FILE *out_file = NULL; // FILE * pointer that would be returned in case of success 68 | char t = 0; // temporary value 69 | 70 | // scanning string 71 | for (file_name = buf; file_name < buf + *length - FILENAME_LEN; file_name++) { 72 | if (memcmp(file_name, FILENAME_STR, FILENAME_LEN) != 0) { 73 | continue; // filename not found, let's go to next loop iteration 74 | } 75 | // filename located, let's adjust pointer to point to start of filename string 76 | file_name += FILENAME_LEN; 77 | // let's locate end of filename string 78 | // TODO we are looking for terminating quote 79 | // TODO this means filename can't have embedded quotes 80 | // TODO not a huge deal for now, but let's not forget about this 81 | file_name_eos = memchr(file_name, '"', *length - (file_name - buf)); 82 | // if terminating quote wasn't found something is wrong 83 | if (file_name_eos == NULL) { 84 | die("Malformed filename in \"%.*s\" string\n", *length, buf); 85 | } 86 | // now let's scan filename starting with end and strip off path if any 87 | for (c = file_name_eos - 1; c > file_name; c--) { 88 | if (*c == '\\' || *c == '/') { 89 | c += 1; 90 | // if filename has path we strip it in place and make string shorter 91 | memmove(file_name, c, *length - (c - buf)); 92 | // we need to update length of the original string so that it would 93 | // be outputted correctly 94 | *length -= (c - file_name); 95 | file_name_eos -= (c - file_name); 96 | break; 97 | } 98 | } 99 | // in order to open file we need 0 terminated string 100 | // so let's save char beyond filename end 101 | t = *file_name_eos; 102 | // substitute it with 0 103 | *file_name_eos = 0; 104 | // open file using write exclusive mode and check if we are good 105 | // if file with this name already exists fopen() would fail 106 | out_file = fopen(file_name, "wx"); 107 | if (out_file == NULL) { 108 | die("Failed to open file %s for writing\n", file_name); 109 | } 110 | // restore char so that original string would be outputted correctly 111 | *file_name_eos = t; 112 | return out_file; 113 | } 114 | return NULL; 115 | } 116 | 117 | // this function processes chunk of data read from stdout 118 | // if this is line from post request (delimited by newlines) 119 | // we use parse_string flag to look for post strings in the line 120 | void process_data(char *buf, int length, int parse_string) { 121 | static int state = STATE_NONE; // parser state 122 | static FILE *out_file = NULL; // can be stdout or post_file 123 | static FILE *post_file = NULL; // file to be saved 124 | static long file_size = 0; // file size, need this to truncate file after save 125 | 126 | // TODO can't init out_file with stdout, may be there is better way to do this 127 | if (out_file == NULL) { 128 | out_file = stdout; 129 | } 130 | // if buf contains string delimited with newlines let's parse it 131 | if (parse_string) { 132 | switch (state) { 133 | // previous line was boundary, we are looking for Content-Disposition 134 | case STATE_BOUNDARY_FOUND: 135 | if (length > CONTENT_DISPOSITION_LEN && memcmp(buf, CONTENT_DISPOSITION_STR, CONTENT_DISPOSITION_LEN) == 0) { 136 | // if found - let's try to find filename 137 | // TODO we could pass (buf + CONTENT_DISPOSITION_LEN, length - CONTENT_DISPOSITION_LEN) 138 | // TODO to save cpu cycles on finding filename in the string, but if filename contains path 139 | // TODO we strip it in place and string becomes shorter. In order to output it correctly 140 | // TODO later in this function we need to change length and in order to do this we need to 141 | // TODO pass not value, but pointer. 142 | post_file = open_file(buf, &length); 143 | // if filename was found and file opened successfully - state is advanced 144 | if (post_file != NULL) { 145 | state = STATE_FILE_OPENED; 146 | break; 147 | } 148 | } 149 | // filename wasn't found, state is reset 150 | state = STATE_NONE; 151 | break; 152 | // previous line was Content-Disposition, next line should be Content-Type 153 | case STATE_FILE_OPENED: 154 | if (length > CONTENT_TYPE_LEN && memcmp(buf, CONTENT_TYPE_STR, CONTENT_TYPE_LEN) == 0) { 155 | state = STATE_CONTENT_TYPE_FOUND; 156 | break; 157 | } 158 | // if Content-Type is not found something is wrong 159 | die("Content type not found\n"); 160 | // previous line was Content-Type, next line should be empty 161 | case STATE_CONTENT_TYPE_FOUND: 162 | if (length == EMPTY_LINE_LEN && memcmp(buf, EMPTY_LINE_STR, EMPTY_LINE_LEN) == 0) { 163 | state = STATE_EMPTY_LINE_FOUND; 164 | break; 165 | } 166 | die("Empty line not found\n"); 167 | // now we are ready to save file 168 | case STATE_EMPTY_LINE_FOUND: 169 | // switching to appropriate state 170 | state = STATE_WRITE_TO_FILE; 171 | // out file is now set to file on disk instead of stdout 172 | out_file = post_file; 173 | // file size is reset 174 | file_size = 0; 175 | break; 176 | // we get here from 2 states: STATE_NONE and STATE_WRITE_TO_FILE 177 | default: 178 | // if boundary was found 179 | if (length > boundary_len && memcmp(buf, boundary_buf, boundary_len) == 0) { 180 | // and we were writing to the file 181 | if (state == STATE_WRITE_TO_FILE) { 182 | // let's flush file buffers 183 | if (fflush(out_file) != 0) { 184 | die("fflush() failed: %s\n", strerror(errno)); 185 | } 186 | // truncate file since last to bytes are 0a 0d from post request 187 | if (ftruncate(fileno(out_file), file_size - 2) != 0) { 188 | die("ftruncate() failed: %s\n", strerror(errno)); 189 | } 190 | // and close file 191 | if (fclose(out_file) != 0) { 192 | die("fclose() failed: %s\n", strerror(errno)); 193 | } 194 | // now let's switch back to stdout for output 195 | post_file = NULL; 196 | out_file = stdout; 197 | } 198 | // and set appropriate state 199 | state = STATE_BOUNDARY_FOUND; 200 | } 201 | } 202 | } 203 | file_size += length; 204 | fwrite(buf, sizeof(char), length, out_file); 205 | } 206 | 207 | // program entry point 208 | int main(int argc, const char* argv[]) { 209 | char data_buf[DATA_BUF_SIZE]; // buffer to read data 210 | int data_len = 0; // how much unprocessed data we have in buffer 211 | char *newline_ptr = NULL; // pointer to newline 212 | char *data_ptr = data_buf; // pointer to start of unprocessed data 213 | int line_len = 0; // length of the line (if found) delimited by newlines 214 | int line_start = 1; // flag: if delimiting newline is present at start of the line 215 | int line_end = 0; // flag: if delimiting newline is present in the end of the line 216 | char *c = NULL; // temporary pointer 217 | 218 | // 1st line is boundary 219 | if (fgets(boundary_buf, BOUNDARY_BUF_SIZE, stdin) == NULL) { 220 | die("Failed to read boundary string\n"); 221 | } 222 | // let's strip terminating \r\n since final boundary line has additional -- in the end 223 | c = memchr(boundary_buf, 0, BOUNDARY_BUF_SIZE); 224 | if (c == NULL) { 225 | die("Boundary string is not 0-terminated\n"); 226 | } 227 | for (c -= 1; c > boundary_buf; c--) { 228 | if (*c != '\r' && *c != '\n') { 229 | break; 230 | } 231 | } 232 | // let's calculate boundary length 233 | boundary_len = c - boundary_buf + 1; 234 | // and output boundary 235 | fputs(boundary_buf, stdout); 236 | // main loop until we read all data from stdin 237 | while (!feof(stdin)) { 238 | // if while prcessing data in the middle of the buffer we found line starting with newline 239 | // but we don't see newline in the end it is possible that we have incomplete line 240 | // so we move all unprocessed data to start of the buffer, read more data into the buffer and try to process it again 241 | data_len = fread(data_ptr, sizeof(char), DATA_BUF_SIZE - (data_ptr - data_buf), stdin) + (data_ptr - data_buf); 242 | data_ptr = data_buf; 243 | // while we have unprocessed data in the buffer 244 | while (data_len > 0) { 245 | // let's find delimiting newline in the buffer 246 | newline_ptr = memchr(data_ptr, '\n', data_len); 247 | // if newline is not found 248 | if (newline_ptr == NULL) { 249 | // and we are in the middle of the buffer 250 | if (data_ptr != data_buf) { 251 | // we move unprocessed data to start of the buffer 252 | memmove(data_buf, data_ptr, data_len); 253 | // and terminate loop 254 | break; 255 | } 256 | // if unprocessed data starts from the beginning of the buffer 257 | // we need to dump it all 258 | line_len = data_len; 259 | // and set flag that there is no newline in the end 260 | line_end = 0; 261 | } else { 262 | // if newline was found let's process string delimited by it 263 | line_len = newline_ptr + 1 - data_ptr; 264 | line_end = 1; 265 | } 266 | // actual data pprocessing 267 | process_data(data_ptr, line_len, line_start && line_end); 268 | // we have less data to process 269 | data_len -= line_len; 270 | // data_ptr should be advanced 271 | data_ptr += line_len; 272 | // flag that line is delimited in the end means that next line is delimited in the beginning 273 | line_start = line_end; 274 | } 275 | // if loop was terminated in the middle data_len is not 0 276 | data_ptr = data_buf + data_len; 277 | } 278 | return 0; 279 | } 280 | -------------------------------------------------------------------------------- /test/001-1kb-test/files/1kb.random: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/001-1kb-test/files/1kb.random -------------------------------------------------------------------------------- /test/001-1kb-test/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/001-1kb-test/stderr -------------------------------------------------------------------------------- /test/001-1kb-test/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/001-1kb-test/stdin -------------------------------------------------------------------------------- /test/001-1kb-test/stdout: -------------------------------------------------------------------------------- 1 | --------------------------d228d4e71067651c 2 | Content-Disposition: form-data; name="file1"; filename="1kb.random" 3 | Content-Type: application/octet-stream 4 | 5 | --------------------------d228d4e71067651c-- 6 | -------------------------------------------------------------------------------- /test/002-empty-test/files/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/002-empty-test/files/empty -------------------------------------------------------------------------------- /test/002-empty-test/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/002-empty-test/stderr -------------------------------------------------------------------------------- /test/002-empty-test/stdin: -------------------------------------------------------------------------------- 1 | --------------------------57c122b925c4b74a 2 | Content-Disposition: form-data; name="file1"; filename="empty" 3 | Content-Type: application/octet-stream 4 | 5 | 6 | --------------------------57c122b925c4b74a-- 7 | -------------------------------------------------------------------------------- /test/002-empty-test/stdout: -------------------------------------------------------------------------------- 1 | --------------------------57c122b925c4b74a 2 | Content-Disposition: form-data; name="file1"; filename="empty" 3 | Content-Type: application/octet-stream 4 | 5 | --------------------------57c122b925c4b74a-- 6 | -------------------------------------------------------------------------------- /test/003-text-test/files/text.txt: -------------------------------------------------------------------------------- 1 | The quick brown fox 2 | jumps over the lazy dog 3 | -------------------------------------------------------------------------------- /test/003-text-test/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/003-text-test/stderr -------------------------------------------------------------------------------- /test/003-text-test/stdin: -------------------------------------------------------------------------------- 1 | --------------------------dde509afacd68cc5 2 | Content-Disposition: form-data; name="file1"; filename="text.txt" 3 | Content-Type: text/plain 4 | 5 | The quick brown fox 6 | jumps over the lazy dog 7 | 8 | --------------------------dde509afacd68cc5-- 9 | -------------------------------------------------------------------------------- /test/003-text-test/stdout: -------------------------------------------------------------------------------- 1 | --------------------------dde509afacd68cc5 2 | Content-Disposition: form-data; name="file1"; filename="text.txt" 3 | Content-Type: text/plain 4 | 5 | --------------------------dde509afacd68cc5-- 6 | -------------------------------------------------------------------------------- /test/004-1kb-text-test/files/1kb.random: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/004-1kb-text-test/files/1kb.random -------------------------------------------------------------------------------- /test/004-1kb-text-test/files/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/004-1kb-text-test/files/empty -------------------------------------------------------------------------------- /test/004-1kb-text-test/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/004-1kb-text-test/stderr -------------------------------------------------------------------------------- /test/004-1kb-text-test/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/004-1kb-text-test/stdin -------------------------------------------------------------------------------- /test/004-1kb-text-test/stdout: -------------------------------------------------------------------------------- 1 | --------------------------98f57122372c39d4 2 | Content-Disposition: form-data; name="file1"; filename="1kb.random" 3 | Content-Type: application/octet-stream 4 | 5 | --------------------------98f57122372c39d4 6 | Content-Disposition: form-data; name="file2"; filename="empty" 7 | Content-Type: application/octet-stream 8 | 9 | --------------------------98f57122372c39d4-- 10 | -------------------------------------------------------------------------------- /test/005-text-1kb-test/files/1kb.random: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/005-text-1kb-test/files/1kb.random -------------------------------------------------------------------------------- /test/005-text-1kb-test/files/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/005-text-1kb-test/files/empty -------------------------------------------------------------------------------- /test/005-text-1kb-test/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/005-text-1kb-test/stderr -------------------------------------------------------------------------------- /test/005-text-1kb-test/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/005-text-1kb-test/stdin -------------------------------------------------------------------------------- /test/005-text-1kb-test/stdout: -------------------------------------------------------------------------------- 1 | --------------------------bffe3bc467fbab0d 2 | Content-Disposition: form-data; name="file1"; filename="empty" 3 | Content-Type: application/octet-stream 4 | 5 | --------------------------bffe3bc467fbab0d 6 | Content-Disposition: form-data; name="file2"; filename="1kb.random" 7 | Content-Type: application/octet-stream 8 | 9 | --------------------------bffe3bc467fbab0d-- 10 | -------------------------------------------------------------------------------- /test/006-field-1kb-text/files/1kb.random: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/006-field-1kb-text/files/1kb.random -------------------------------------------------------------------------------- /test/006-field-1kb-text/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/006-field-1kb-text/stderr -------------------------------------------------------------------------------- /test/006-field-1kb-text/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/006-field-1kb-text/stdin -------------------------------------------------------------------------------- /test/006-field-1kb-text/stdout: -------------------------------------------------------------------------------- 1 | --------------------------d98d873b7f43db1d 2 | Content-Disposition: form-data; name="param1" 3 | 4 | test value1 5 | --------------------------d98d873b7f43db1d 6 | Content-Disposition: form-data; name="file1"; filename="1kb.random" 7 | Content-Type: application/octet-stream 8 | 9 | --------------------------d98d873b7f43db1d-- 10 | -------------------------------------------------------------------------------- /test/007-1kb-field-test/files/1kb.random: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/007-1kb-field-test/files/1kb.random -------------------------------------------------------------------------------- /test/007-1kb-field-test/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/007-1kb-field-test/stderr -------------------------------------------------------------------------------- /test/007-1kb-field-test/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/007-1kb-field-test/stdin -------------------------------------------------------------------------------- /test/007-1kb-field-test/stdout: -------------------------------------------------------------------------------- 1 | --------------------------3b31e7bac235d21a 2 | Content-Disposition: form-data; name="file1"; filename="1kb.random" 3 | Content-Type: application/octet-stream 4 | 5 | --------------------------3b31e7bac235d21a 6 | Content-Disposition: form-data; name="param1" 7 | 8 | test value1 9 | --------------------------3b31e7bac235d21a-- 10 | -------------------------------------------------------------------------------- /test/008-field-1kb-field-test/files/1kb.random: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/008-field-1kb-field-test/files/1kb.random -------------------------------------------------------------------------------- /test/008-field-1kb-field-test/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/008-field-1kb-field-test/stderr -------------------------------------------------------------------------------- /test/008-field-1kb-field-test/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/008-field-1kb-field-test/stdin -------------------------------------------------------------------------------- /test/008-field-1kb-field-test/stdout: -------------------------------------------------------------------------------- 1 | --------------------------da398c7d53440a86 2 | Content-Disposition: form-data; name="param2" 3 | 4 | test value2 5 | --------------------------da398c7d53440a86 6 | Content-Disposition: form-data; name="file1"; filename="1kb.random" 7 | Content-Type: application/octet-stream 8 | 9 | --------------------------da398c7d53440a86 10 | Content-Disposition: form-data; name="param1" 11 | 12 | test value1 13 | --------------------------da398c7d53440a86-- 14 | -------------------------------------------------------------------------------- /test/009-1kb-field-text-test/files/1kb.random: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/009-1kb-field-text-test/files/1kb.random -------------------------------------------------------------------------------- /test/009-1kb-field-text-test/files/text.txt: -------------------------------------------------------------------------------- 1 | The quick brown fox 2 | jumps over the lazy dog 3 | -------------------------------------------------------------------------------- /test/009-1kb-field-text-test/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/009-1kb-field-text-test/stderr -------------------------------------------------------------------------------- /test/009-1kb-field-text-test/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/009-1kb-field-text-test/stdin -------------------------------------------------------------------------------- /test/009-1kb-field-text-test/stdout: -------------------------------------------------------------------------------- 1 | --------------------------04673519c52c015c 2 | Content-Disposition: form-data; name="file1"; filename="1kb.random" 3 | Content-Type: application/octet-stream 4 | 5 | --------------------------04673519c52c015c 6 | Content-Disposition: form-data; name="param1" 7 | 8 | test value1 9 | --------------------------04673519c52c015c 10 | Content-Disposition: form-data; name="files"; filename="text.txt" 11 | Content-Type: text/plain 12 | 13 | --------------------------04673519c52c015c-- 14 | -------------------------------------------------------------------------------- /test/010-field-1kb-field-text-field-test/files/1kb.random: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/010-field-1kb-field-text-field-test/files/1kb.random -------------------------------------------------------------------------------- /test/010-field-1kb-field-text-field-test/files/text.txt: -------------------------------------------------------------------------------- 1 | The quick brown fox 2 | jumps over the lazy dog 3 | -------------------------------------------------------------------------------- /test/010-field-1kb-field-text-field-test/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/010-field-1kb-field-text-field-test/stderr -------------------------------------------------------------------------------- /test/010-field-1kb-field-text-field-test/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/test/010-field-1kb-field-text-field-test/stdin -------------------------------------------------------------------------------- /test/010-field-1kb-field-text-field-test/stdout: -------------------------------------------------------------------------------- 1 | --------------------------9c2f6b4480795390 2 | Content-Disposition: form-data; name="param2" 3 | 4 | test value2 5 | --------------------------9c2f6b4480795390 6 | Content-Disposition: form-data; name="file1"; filename="1kb.random" 7 | Content-Type: application/octet-stream 8 | 9 | --------------------------9c2f6b4480795390 10 | Content-Disposition: form-data; name="param1" 11 | 12 | test value1 13 | --------------------------9c2f6b4480795390 14 | Content-Disposition: form-data; name="files"; filename="text.txt" 15 | Content-Type: text/plain 16 | 17 | --------------------------9c2f6b4480795390-- 18 | -------------------------------------------------------------------------------- /test/run-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -u -e 4 | 5 | script_dir=$(cd "$(dirname $0)" && pwd) 6 | test_binary="${script_dir}/../extract-post-file" 7 | test_run_dir=/tmp/tmp-$$ 8 | 9 | tests_passed=0 10 | tests_failed=0 11 | 12 | mkdir -p $test_run_dir 13 | 14 | for test_dir in $script_dir/[0-9]*-test; do 15 | test_name=$(basename ${test_dir}) 16 | mkdir -p ${test_run_dir}/${test_name}/files 17 | cp $test_dir/stdin ${test_run_dir}/${test_name} 18 | ( cd ${test_run_dir}/${test_name}/files && $test_binary < ../stdin > ../stdout 2> ../stderr ) 19 | if diff -r ${test_run_dir}/${test_name} $test_dir ; then 20 | echo "$test_name ok" 21 | ((tests_passed++)) || true 22 | else 23 | echo "$test_name failed" 24 | ((tests_failed++)) || true 25 | fi 26 | done 27 | 28 | rm -rf $test_run_dir 29 | echo "Summary: $tests_passed tests passed, $tests_failed tests failed" 30 | ((tests_failed != 0)) && exit 1 31 | exit 0 32 | -------------------------------------------------------------------------------- /usr/bin/urepo-upload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -u -e 3 | 4 | BASENAME=$(basename $0) 5 | CONFIGS="$HOME/.${BASENAME}.conf /etc/skel/.${BASENAME}.conf" 6 | 7 | usage() { 8 | echo "Usage: ${BASENAME} -d DIST -b BRANCH pkg_path" 9 | echo " DIST should be name of distribution supported on your repository (e.g centos6, precise etc)" 10 | echo " BRANCH should be stable, testing or anything else supported on your repository" 11 | echo 12 | echo " This utility uses configuration file .${BASENAME}.conf. It looks" 13 | echo " for it in home directory and if not found in /etc/skel/." 14 | echo " Configuration file should define following environment variables:" 15 | echo " UREPO_SERVER - name or ip address of server where we want to upload packages (via ssh)" 16 | echo " UREPO_UPLOAD_DIR - location of upload dir on server" 17 | exit 18 | } 19 | 20 | trap 'usage' ERR 21 | 22 | load_config() { 23 | for config in $CONFIGS; do 24 | [ -r $config ] && . $config && return 25 | done 26 | echo "Couldn't find config file" 27 | usage 28 | } 29 | 30 | load_config 31 | 32 | while [ -n "${1:-}" ]; do 33 | case $1 in 34 | -d) shift && dist=$1 && shift ;; 35 | -b) shift && branch=$1 && shift ;; 36 | *) pkg_path=$1 && shift ;; 37 | esac 38 | done 39 | 40 | pkg_name=$(basename $pkg_path) 41 | cat $pkg_path |ssh $UREPO_SERVER "cd $UREPO_UPLOAD_DIR && \ 42 | cat - >$pkg_name && \ 43 | curl -X POST -s -F dist=$dist -F branch=$branch -F file1=$pkg_name http://127.0.0.1/cgi/process-file" 44 | exit $? 45 | -------------------------------------------------------------------------------- /var/urepo/cgi/process-file: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit on errors immediately, do not tolerate unbound variables 4 | set -u -e 5 | 6 | # merge stderr with stdout 7 | exec 2>&1 8 | 9 | # start of http response 10 | echo "Content-Type: text/plain" 11 | echo 12 | 13 | CONFIG=/etc/urepo/urepo.conf 14 | 15 | . $CONFIG || { 16 | echo "Error: failed to load $CONFIG" 17 | exit 18 | } 19 | 20 | cgi_dir=$(cd $(dirname $0) && pwd) 21 | 22 | . $cgi_dir/urepo-functions 23 | 24 | cd $UREPO_UPLOAD_DIR 25 | 26 | # if upload dir contains files not processed for 1 hour - those are deleted 27 | find $UREPO_UPLOAD_DIR -type f -amin +60 -exec rm -f {} \; 28 | 29 | method=${REQUEST_METHOD,,} 30 | # post-file-extract saves uploaded file to current dir, remaining post request goes through unchanged 31 | # awk is used to extract parameters from post request in form "declare var=val" 32 | # those declarations are executed in current shell context, since strings are not evaluated this is secure 33 | case "$method" in 34 | post) cmd="$cgi_dir/extract-post-file" ;; 35 | delete) 36 | [ "$HTTP_HOST" != "127.0.0.1" ] && log "Error: delete from $HTTP_HOST is prohibited" && exit 37 | cmd=cat 38 | ;; 39 | *) log "Error: method \"$method\" is not supported" && exit ;; 40 | esac 41 | 42 | . <($cmd|awk 'BEGIN {getline RS; RS = RS "?(--)?\r\n";} {gsub(/[\n\r]/, ""); sub(/.* name=\"/, "declare "); sub(/\"Content-Type: .*/, ""); sub(/; [^\"]*\"/, ""); sub(/\"/, "=\""); sub(/$/, "\""); print;}') 43 | [ -z "${file1:-}" ] && log "Error: failed to extract file from post request" && exit 44 | file1_path="$UREPO_UPLOAD_DIR/$file1" 45 | 46 | # if we are not oldest script instance running let's wait for earlier instances to complete 47 | while [ "$$" != "$(pgrep -o -f $0)" ] ; do 48 | sleep 1 49 | done 50 | 51 | # let's figure out file extension 52 | ext="${file1##*.}" 53 | # and determine handler for this file 54 | handler="${method}_${ext}" 55 | # if handler exists - let's proceed, otherwise we report error and delete file 56 | if type -t "$handler" | grep -q function; then 57 | "$handler" 58 | else 59 | log "Error: no handler found for \"$file1\"" 60 | rm -f "$file1_path" 61 | fi 62 | -------------------------------------------------------------------------------- /var/urepo/cgi/urepo-functions: -------------------------------------------------------------------------------- 1 | log() { 2 | echo "$1" >&2 3 | echo "$(date +"%Y-%m-%d %H:%M:%S") ${REMOTE_ADDR:-unknown} $1" >>$UREPO_LOG 4 | } 5 | 6 | generate_pkg_control() { 7 | local pkg_path="$1" 8 | control_file=$(ar t "$pkg_path"|grep ^control) 9 | [ -z "$control_file" ] && { 10 | log "Error: control data not found in \"$pkg_path\"" 11 | rm -f "$pkg_path" 12 | return 1 13 | } 14 | case "$control_file" in 15 | *.tar.gz) 16 | tar_options="-Ozxf" 17 | ;; 18 | *.tar.xz) 19 | tar_options="-OJxf" 20 | ;; 21 | *) 22 | log "Error: unsupported format of the control data in \"$pkg_path\"" 23 | rm -f "$pkg_path" 24 | return 1 25 | ;; 26 | esac 27 | pkg_data=$(ar p "$pkg_path" "$control_file"|tar --no-anchored $tar_options - control) || { 28 | log "Error: failed to extract control data from \"$pkg_path\"" 29 | rm -f "$pkg_path" 30 | return 1 31 | } 32 | 33 | pkg_name=$(echo "$pkg_data"|grep "^Package:"|awk '{print $2}') 34 | pkg_version=$(echo "$pkg_data"|grep "^Version:"|awk '{print $2}') 35 | pkg_arch=$(echo "$pkg_data"|grep "^Architecture:"|awk '{print $2}') 36 | full_pkg_name=${pkg_name}_${pkg_version}_${pkg_arch}.deb 37 | new_pkg_path="$(dirname "$pkg_path")/$full_pkg_name" 38 | 39 | pkg_data+=" 40 | Filename: $new_pkg_path 41 | Size: $(stat -c %s "$pkg_path") 42 | MD5sum: $(md5sum $pkg_path|awk '{print $1}') 43 | SHA1: $(sha1sum $pkg_path|awk '{print $1}') 44 | SHA256: $(sha256sum $pkg_path|awk '{print $1}') 45 | SHA512: $(sha512sum $pkg_path|awk '{print $1}') 46 | " 47 | if [ "$pkg_path" != "$new_pkg_path" ] ; then 48 | log "Info: renaming \"$pkg_path\" to \"$new_pkg_path\"" 49 | (ln -P "$pkg_path" "$new_pkg_path" && rm -f "$pkg_path") || { 50 | log "Error: can't overwrite \"$new_pkg_path\" with \"$pkg_path\", deleting latter" 51 | rm -f "$pkg_path" 52 | return 1 53 | } 54 | fi 55 | echo "$pkg_data" > "${new_pkg_path}.control" 56 | return 0 57 | } 58 | 59 | generate_release() { 60 | local size 61 | declare -A checksum=( 62 | [MD5Sum]=md5sum 63 | [SHA1]=sha1sum 64 | [SHA256]=sha256sum 65 | [SHA512]=sha512sum 66 | ) 67 | echo "Codename: $dist 68 | Date: $(date -u +"%a, %d %b %Y %T %Z") 69 | Suite: $dist" 70 | cd $DEB_REPO_ROOT/dists/$dist 71 | for label in ${!checksum[@]}; do 72 | echo "${label}:" 73 | for pkg_data in */binary-*/Packages*; do 74 | size=$(stat -c %s $pkg_data) 75 | ${checksum[$label]} $pkg_data|awk -vsize=$size '{printf(" %s %16d %s\n", $1, size, $2)}' 76 | done 77 | done 78 | } 79 | 80 | generate_repo_data() { 81 | local arch pkg failures=0 82 | cd $DEB_REPO_ROOT 83 | for pkg in $(find pool/$dist/$branch/ -type f -regex ".*[.]deb$"); do 84 | [ -r "${pkg}.control" ] && continue 85 | generate_pkg_control "$pkg" || ((failures++)) 86 | done 87 | for arch in i386 amd64; do 88 | find $DEB_REPO_ROOT/pool/$dist/$branch/ -type f -regex ".*_\($arch\|all\)[.]deb[.]control$" -exec cat {} \; >$DEB_REPO_ROOT/dists/$dist/$branch/binary-${arch}/Packages 89 | gzip -c $DEB_REPO_ROOT/dists/$dist/$branch/binary-${arch}/Packages >$DEB_REPO_ROOT/dists/$dist/$branch/binary-${arch}/Packages.gz 90 | bzip2 -c $DEB_REPO_ROOT/dists/$dist/$branch/binary-${arch}/Packages >$DEB_REPO_ROOT/dists/$dist/$branch/binary-${arch}/Packages.bz2 91 | done 92 | generate_release >$DEB_REPO_ROOT/dists/$dist/Release 93 | return "$failures" 94 | } 95 | 96 | post_deb() { 97 | pool_dir="$DEB_REPO_ROOT/pool/$dist/$branch" 98 | 99 | [ -d "$pool_dir" ] || { 100 | log "Error: bad pool directory: $pool_dir" 101 | rm -f "$file1_path" 102 | return 103 | } 104 | target="${pool_dir}/$(basename "$file1_path")" 105 | (set -C && cat "$file1_path" > "${target}") || { 106 | log "Error: file \"${target}\" already exists, can't overwrite" 107 | rm -f "$file1_path" 108 | return 109 | } 110 | 111 | rm -f "$file1_path" 112 | chmod 0644 "$target" 113 | 114 | generate_repo_data || { 115 | log "Warning: issues encountered while adding $target" 116 | return 117 | } 118 | log "Info: $target added ok" 119 | } 120 | 121 | delete_deb() { 122 | cd $DEB_REPO_ROOT 123 | 124 | [ -r "pool/$dist/$branch/$file1" ] || { 125 | log "Error: file $file1 not found" 126 | exit 127 | } 128 | 129 | rm -f "pool/${dist}/${branch}/${file1}" 130 | rm -f "pool/${dist}/${branch}/${file1}.control" 131 | 132 | if generate_repo_data; then 133 | log "Info: $file1 deleted ok" 134 | else 135 | log "Warning: issues encountered while deleting $file1" 136 | fi 137 | } 138 | 139 | post_rpm() { 140 | pkg_data=$(rpm -qpi $file1_path 2>&1) || { 141 | log "Error: $file1_name is not rpm package" 142 | rm -f $file1_path 143 | exit 144 | } 145 | pkg_name=$(echo "$pkg_data"|grep "^Name *: "|awk '{print $3}') 146 | pkg_version=$(echo "$pkg_data"|grep "^Version"|awk '{print $3}') 147 | pkg_arch=$(echo "$pkg_data"|grep "^Architecture:"|awk '{print $2}') 148 | pkg_release=$(echo "$pkg_data"|grep "^Release"|awk '{print $3}') 149 | full_pkg_name=${pkg_name}-${pkg_version}-${pkg_release}.${pkg_arch}.rpm 150 | 151 | dirs="" 152 | case $pkg_arch in 153 | noarch) for dir in $RPM_REPO_ROOT/$dist/$branch/*; do 154 | [[ "$dir" =~ SRPMS$ ]] || dirs+="$dir " 155 | done 156 | ;; 157 | i[56]86) dirs=$RPM_REPO_ROOT/$dist/$branch/i386 ;; 158 | *) dirs=$RPM_REPO_ROOT/$dist/$branch/$pkg_arch ;; 159 | esac 160 | 161 | for dir in $dirs; do 162 | [ -d "$dir" ] || { 163 | log "Error: no such directory: $dir" 164 | rm -f $file1_path 165 | exit 166 | } 167 | [ -r "$dir/$full_pkg_name" ] && { 168 | log "Error: file $dir/$full_pkg_name already exists, can't overwrite" 169 | rm -f $file1_path 170 | exit 171 | } 172 | done 173 | 174 | cp $file1_path ${file1_path}$$ 175 | mv -f ${file1_path}$$ $file1_path 176 | chmod 0644 $file1_path 177 | 178 | # For packages that get added to multiple architectures (e.g., the same 179 | # package ends up in both i386 and x86_64), a hard link to the uploaded 180 | # package saves space but will fail when crossing file system boundaries; 181 | # what this does is copy the first instance unconditionally and attempt to 182 | # hard link subsequent instances, falling back to copying if linking fails. 183 | idx=0 184 | for dir in $dirs; do 185 | if [ $idx -eq 0 ]; then 186 | cp -f $file1_path $dir/$full_pkg_name 187 | newpath=$dir/$full_pkg_name 188 | idx=1 189 | else 190 | ln -f $newpath $dir/$full_pkg_name || cp -f $file1_path $dir/$full_pkg_name 191 | fi 192 | createrepo -s sha -q -c $dir/.cache $dir 193 | done 194 | 195 | log "Info: $full_pkg_name added ok" 196 | rm -f $file1_path 197 | } 198 | 199 | delete_rpm() { 200 | [ -z "$(ls $RPM_REPO_ROOT/$dist/$branch/*/$file1 2>/dev/null)" ] && log "$file1 not found" && exit 201 | 202 | rm -f $RPM_REPO_ROOT/$dist/$branch/*/$file1 $RPM_REPO_ROOT/$dist/$branch/*/.cache/${file1}-* 203 | 204 | for dir in $RPM_REPO_ROOT/$dist/$branch/*; do 205 | createrepo -s sha -q -c $dir/.cache $dir 206 | done 207 | 208 | log "Info: $file1 deleted" 209 | } 210 | -------------------------------------------------------------------------------- /var/urepo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hulu/urepo/cda0a1e97a90f9bf2cd7d3e78b2943c64d88c815/var/urepo/favicon.ico -------------------------------------------------------------------------------- /var/urepo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Select file to upload to repository 5 | 6 | 28 | 29 | 30 |

Select file to upload to repository

31 |
32 | 33 | 34 | 35 | 36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /var/urepo/jquery.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license 2 | //@ sourceMappingURL=jquery.min.map 3 | */(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
a",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="
t
",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},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(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj; 4 | return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="
",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:b.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l) 5 | }b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("