├── LICENSE ├── README.md ├── assembly-stats.html ├── css ├── circle-plot.css ├── square-plot.css └── table.css ├── js ├── circle-plot.js ├── d3-tip.js ├── d3.js ├── jquery.min.js ├── square-plot.js └── table.js ├── json ├── Danaus_plexippus_v3.assembly-stats.json ├── Heliconius_erato_v1.assembly-stats.json └── Operophtera_brumata_v1.assembly-stats.json ├── pl ├── asm2stats.minmaxgc.pl └── asm2stats.pl └── screenshots ├── assembly_stats.png ├── circle.png ├── cumulative.png └── table.png /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016 Richard Challis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # assembly-stats 2 | 3 | ========================================================================= 4 | 5 | ## Updated code available 6 | 7 | The code in this repository is no longer actively maintained. The latest code for generating snail plots is part of the [BlobToolKit](https://github.com/blobtoolkit/blobtoolkit) project. BlobToolKit supports interactive (see the [public viewer instance](https://blobtoolkit.genomehubs.org/view) and static assembly visualisation. To generate an assembly-stats snail plot on the command line, [install blobtoolkit](https://github.com/blobtoolkit/blobtoolkit/wiki/Installation) and follow the [command line instructions](https://github.com/blobtoolkit/blobtoolkit/wiki/Snail-plot#command-line) 8 | 9 | ========================================================================= 10 | 11 | # Legacy code README 12 | 13 | [![DOI](https://zenodo.org/badge/20772/rjchallis/assembly-stats.svg)](https://zenodo.org/badge/latestdoi/20772/rjchallis/assembly-stats) 14 | 15 | Assembly metric visualisations to facilitate rapid assessment and comparison of assembly quality. 16 | 17 | [Live demo](http://content.lepbase.org/html/assembly-stats/assembly-stats.html?path=/v4/json/assemblies/&assembly=Danaus_plexippus_v3&view=circle&altAssembly=Danaus_plexippus_DanPle_1.0&altView=compare&altAssembly=Heliconius_melpomene_melpomene_Hmel2&altView=cumulative&altView=table) 18 | 19 | Latest and most complete documentation is available at [assembly-stats.readme.io](http://assembly-stats.readme.io) 20 | 21 | 22 | ## Description 23 | 24 | A _de novo_ genome assembly can be summarised by a number of metrics, including: 25 | - Overall assembly length 26 | - Number of scaffolds/contigs 27 | - Length of longest scaffold/contig 28 | - Scaffold/contig N50 and N90 29 | - Assembly base composition, in particular percentage GC and percentage Ns 30 | - CEGMA completeness 31 | - Scaffold/contig length/count distribution 32 | 33 | assembly-stats supports two widely used presentations of these values, tabular and cumulative length plots, and introduces an additional circular plot that summarises most commonly used assembly metrics in a single visualisation. Each of these presentations is generated using javascript from a common (JSON) data structure, allowing toggling between alternative views, and each can be applied to a single or multiple assemblies to allow direct comparison of alternate assemblies. 34 | 35 | Tabular presentation allows direct comparison of exact values between assemblies, the limitations of this approach lie in the necessary omission of distributions and the challenge of interpreting ratios of values that may vary by several orders of magnitude. 36 | 37 | ![Screenshot](/screenshots/table.png "Table view") 38 | 39 | Cumulative scaffold length plots are highly effective for comparison of two or more assemblies, plotting both on a single set of axes reveals differences in assembled size and the N50 count very clearly. However, other metrics must still be tabulated or annotated on the plot for example N50 length and the longest scaffold length can be particularly difficult to determine from the plot alone. The scale for the axes is usually chosen to accommodate the data for a single assembly or set of assemblies, meaning that it is usually necessary to replot the data or consider the relative axis scales carefully to compare assemblies that have been plotted separately. The cumulative distribution plots in assembly-stats address the problem of scaling by allowing any combination of assemblies to be plotted together and allowing rescaling of the axes to fit any one of the individual assemblies. 40 | 41 | ![Screenshot](/screenshots/cumulative.png "Cumulative view") 42 | 43 | The circular plots have been introduced to overcome some of the shortcomings of tabular and cumulative distribution plots in a visualisation that allows rapid assessment of most common assembly metrics. The graphic is essentially scale independent so assemblies of any size with different strengths and weaknesses produce distinct patterns that can be recognised at a glance. While side by side presentation of a pair of assemblies on consistently scaled axes allows direct comparison, the standard presentation is designed to facilitate assessment of overall assembly quality by consideration of the keys features from the plot. 44 | 45 | ![Screenshot](/screenshots/circle.png "Circle view") 46 | 47 | 48 | ## plot descritption 49 | - click on any colour tile in the legend to toggle visibility of that feature on/off 50 | - The inner radius of the circular plot represents the length of the longest scaffold in the assembly 51 | - The angle subtended by the first (red) segment within this plot indicates the percentage of the assembly that is in the longest scaffold 52 | - The radial axis originates at the circumference and indicates scaffold length 53 | - Subsequent (grey) segments are plotted from the circumference and the length of segment at a given percentage indicates the cumulative percentage of the assembly that is contained within scaffolds of at least that length 54 | - The N50 and N90 scaffold lengths are indicated respectively by dark and light orange arcs that connect to the radial axis for ease of comparison 55 | - The cumulative number of scaffolds within a given percentge of the genome is plotted in purple originating at the centre of the plot 56 | - White scale lines are drawn at successive orders of magnitude from 10 scaffolds onwards 57 | - The fill colour of the circumferential axis indicates the percentage base composition of the assembly: AT = light blue; GC = dark blue; N = grey 58 | - Contig length (if available) is indicated by darker grey segments overlaying the scaffold length plot 59 | - Contig count (if available) may be toggled on to be shown in place of the scaffold count plot 60 | - Complete, fragmented and duplicated BUSCO genes (if available) are shown in mid, light and dark green, respectively in the smaller plot in the upper right corner 61 | - Partial and complete CEGMA values (if available) are shown in light and dark green, respectively in the smaller plot in the upper right corner 62 | 63 | ## basic usage 64 | 65 | ### input format 66 | 67 | Data to be plotted must be supplied as a JSON format object. As of version 1.1 data may be pre-binned to improve performance with assemblies containing potentially millions of contigs. The simplest way to generate this is using the ``asm2stats.pl`` or ``asm2stats.minmaxgc.pl`` perl scripts in the ``pl`` folder: 68 | 69 | ```bash 70 | perl asm2stats.pl genome_assembly.fa > output.assembly-stats.json 71 | perl asm2stats.minmaxgc.pl genome_assembly.fa > output.assembly-stats.json 72 | ``` 73 | 74 | This input format should be preferred as it improves performance and corrects for a bug in the javascript binning code by adjusting bin size to accommodate assembly spans that are not divisible by 1000, however the previous input format (with a full list of scaffold lengths is still supported). 75 | 76 | 77 | ### usage 78 | 79 | The simplest plot requires a target div, an assembly span, a count of ACGT bases, the GC percentage and an array of scaffold lengths, however it is best to use the ``asm2stats.pl``/``asm2stats.minmaxgc.pl`` perl scripts described above to generate a richer, pre-processed input format. See the ``Danaus_plexippus_v3.assembly-stats.json`` file for a complete example using pre-binned data, basic usage is detailed below: 80 | 81 | ```html 82 |
83 | 90 | ``` 91 | 92 | If called using javascript in a custom html file as above, the file can have any name, but for use with the example `assembly-stats.html` file, the json filename should match the pattern `.assembly-stats.json`. This needs to be hosted as a webpage in order to run, if you would rather run this using github pages than set up a local webserver, follow the instructions by [@ammaraziz](https://github.com/ammaraziz) in [this fork](https://github.com/ammaraziz/assembly-stats). 93 | 94 | Alternatively use python `http.server` as suggested by [@hung-th](https://github.com/hung-th) by executing the command `python -m http.server 8080` in the assembly-stats directory, then visit `http://0.0.0.0:8080/assembly-stats.html?path=json/&assembly=output&view=circle&altView=cumulative&altView=table` in a web browser (assuming the json file is named `output.assembly-stats.json`). 95 | 96 | The json object contains the following keys: 97 | - ``assembly`` - the total assembly span 98 | - ``ATGC`` - the assembly span without Ns (redundant if ``N`` is specified) 99 | - ``GC`` - the GC percentage of the assembly 100 | - ``N`` - the total number of Ns (redundant if ``ATGC`` is specified) 101 | - ``scaffold_count`` - the total number of scaffolds in the assembly 102 | - ``scaffolds`` - an array of scaffold lengths (only the longest scaffold is needed if ``binned_scaffold_lengths`` and ``binned_scaffold_counts`` are specified) 103 | - ``binned_scaffold_lengths`` - an array of 1000 scaffold lengths representing the N0.1 to N100 scaffold lengths for the assembly 104 | - ``binned_scaffold_counts`` - an array of 1000 scaffold counts representing the N0.1 to N100 scaffold numbers for the assembly 105 | - ``contig_count`` - (optional) the total number of contigs in the assembly 106 | - ``contigs`` - (optional) an array of contig lengths (only the longest contig is needed if ``binned_contig_lengths`` and ``binned_contig_counts`` are specified) 107 | - ``binned_contig_lengths`` - (optional) an array of 1000 contig lengths representing the N0.1 to N100 contig lengths for the assembly 108 | - ``binned_contig_counts`` - (optional) an array of 1000 contig counts representing the N0.1 to N100 contig numbers for the assembly 109 | - ``binned_Ns`` - (optional) an array of 1000 values representing the N content of each bin based on size-sorted scaffold sequences 110 | - ``binned_GCs`` - (optional) an array of 1000 values representing the GC content of each bin based on size-sorted scaffold sequences 111 | 112 | 113 | Additional data will be plotted, if added to the stats object including: 114 | - CEGMA scores 115 | 116 | ```json 117 | "cegma_complete": 83.87, 118 | "cegma_partial": 95.16 119 | ``` 120 | 121 | - BUSCO complete, duplicated, fragmented, missing and number of genes (will be plotted in place of CEGMA if both are present) 122 | 123 | ```json 124 | "busco": { 125 | "C": 87.1, 126 | "D": 3.6, 127 | "F": 10.1, 128 | "M": 2.8, 129 | "n": 2675 130 | }, 131 | ``` 132 | 133 | While the plots were conceived as scale independent visualisations, there are occasions when it is useful to compare assemblies on the same radial (longest scaffold) or circumferential (assembly span) scales. These scales may be modified on the plot by clicking the grey boxes under the scale heading. Plots can also be drawn with an specific scale by supplying additional arguments to ``drawPlot()``. 134 | 135 | For example to scale the radius to 10 Mb and the circumference to 400 Mb (values smaller than the default will be ignored): 136 | 137 | ```javascript 138 | asm.drawPlot('assembly_stats',10000000,400000000); 139 | ``` 140 | 141 | It is also possible to programmatically toggle the visibility of plot features by passing an array of classnames to ``toggleVisible()``: 142 | 143 | ```javascript 144 | asm.toggleVisible(['asm-longest_pie','asm-count']); 145 | ``` 146 | -------------------------------------------------------------------------------- /assembly-stats.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | assembly stats 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 72 | 73 |
74 | 75 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /css/circle-plot.css: -------------------------------------------------------------------------------- 1 | rect { 2 | -webkit-box-sizing: border-box; 3 | -moz-box-sizing: border-box; 4 | box-sizing: border-box; 5 | cursor: pointer; 6 | } 7 | .hidden { 8 | visibility: hidden; 9 | } 10 | .asm-ns { 11 | stroke: #dddddd; 12 | stroke-width: 0px; 13 | fill: #dddddd; 14 | } 15 | .asm-genome { 16 | stroke: rgb(177, 89, 40); 17 | stroke-width: 0px; 18 | fill: rgb(255, 255, 255); 19 | visibility: hidden; 20 | } 21 | .asm-genome.asm-toggle { 22 | visibility: visible; 23 | } 24 | .asm-assembly { 25 | stroke: rgb(212, 168, 122); 26 | stroke-width: 0px; 27 | fill: rgb(255, 255, 255); 28 | visibility: hidden; 29 | } 30 | .asm-assembly.asm-toggle { 31 | visibility: visible; 32 | } 33 | .asm-atgc { 34 | stroke: rgb(166, 206, 227); 35 | stroke-width: 0px; 36 | fill: rgb(166, 206, 227); 37 | } 38 | .asm-gc { 39 | stroke: rgb(31, 120, 180); 40 | stroke-width: 0px; 41 | fill: rgb(31, 120, 180); 42 | } 43 | .asm-atgc-line { 44 | stroke: rgb(166, 206, 227); 45 | stroke-width: 0.25px; 46 | fill: none; 47 | } 48 | .asm-gc-line { 49 | stroke: rgb(31, 120, 180); 50 | stroke-width: 0.5px; 51 | fill: none; 52 | } 53 | .asm-busco_C { 54 | stroke: rgb(51, 160, 44); 55 | stroke-width: 0px; 56 | fill: rgb(51, 160, 44); 57 | } 58 | .asm-busco_F { 59 | stroke: rgb(178, 223, 138); 60 | stroke-width: 0px; 61 | fill: rgb(178, 223, 138); 62 | } 63 | .asm-busco_D { 64 | stroke: rgb(35, 108, 30); 65 | stroke-width: 0px; 66 | fill: rgb(35, 108, 30); 67 | } 68 | .asm-ceg_comp { 69 | stroke: rgb(51, 160, 44); 70 | stroke-width: 0px; 71 | fill: rgb(51, 160, 44); 72 | } 73 | .asm-ceg_part { 74 | stroke: rgb(178, 223, 138); 75 | stroke-width: 0px; 76 | fill: rgb(178, 223, 138); 77 | } 78 | .asm-ceg_line { 79 | stroke: #555555; 80 | stroke-width: 0.67px; 81 | fill: none; 82 | opacity: 0; 83 | } 84 | .asm-contig_count { 85 | stroke: rgb(153, 135, 163); 86 | stroke-width: 0px; 87 | fill: rgb(153, 135, 163); 88 | visibility: hidden; 89 | } 90 | .asm-contig_count.asm-toggle { 91 | visibility: visible; 92 | fill: rgb(255, 255, 255); 93 | } 94 | .asm-count { 95 | stroke: rgb(202, 178, 214); 96 | stroke-width: 0px; 97 | fill: rgb(202, 178, 214); 98 | } 99 | .asm-count_axis { 100 | stroke: white; 101 | stroke-width: 2px; 102 | fill: none; 103 | } 104 | .asm-length_axis { 105 | stroke: #555555; 106 | stroke-width: 0.67px; 107 | fill: none; 108 | opacity: 0.6; 109 | } 110 | .asm-n50_pie { 111 | stroke: rgb(255, 127, 0); 112 | stroke-width: 0px; 113 | fill: rgb(255, 127, 0); 114 | } 115 | .asm-n90_pie { 116 | stroke: rgb(253, 191, 111); 117 | stroke-width: 0px; 118 | fill: rgb(253, 191, 111); 119 | } 120 | .asm-longest_pie { 121 | stroke: rgb(227, 26, 28); 122 | stroke-width: 0px; 123 | fill: rgb(227, 26, 28)/*rgb(51,160,44)*/ 124 | ; 125 | } 126 | .asm-live_segment { 127 | stroke: none; 128 | stroke-width: 0px; 129 | fill: rgb(217, 217, 217); 130 | opacity: 0.4; 131 | } 132 | .asm-contig { 133 | stroke: #999999; 134 | stroke-width: 0px; 135 | fill: #999999; 136 | visibility: hidden; 137 | } 138 | .asm-contig.asm-toggle { 139 | visibility: visible; 140 | fill: rgb(255, 255, 255); 141 | } 142 | .asm-toggle { 143 | stroke-width: 2px; 144 | } 145 | .asm-highlight { 146 | stroke-width: 2px; 147 | } 148 | #asm-g-scaffold_length_highlight { 149 | opacity: 1; 150 | } 151 | #asm-g-contig_length_data {} 152 | .asm-pie { 153 | stroke: #bbbbbb; 154 | stroke-width: 2px; 155 | fill: #bbbbbb; 156 | } 157 | .asm-majorTick { 158 | stroke: #555555; 159 | stroke-width: 2px; 160 | fill: none; 161 | } 162 | .asm-minorTick { 163 | stroke: #555555; 164 | fill: none; 165 | } 166 | .asm-axis { 167 | stroke: #555555; 168 | stroke-width: 2px; 169 | fill: none; 170 | } 171 | .asm-narrow { 172 | stroke: #999999; 173 | stroke-width: 1px; 174 | } 175 | .asm-live_stats { 176 | fill: white; 177 | } 178 | .asm-scale_rect { 179 | fill: #eeeeee; 180 | stroke: #999999; 181 | stroke-width: 1px; 182 | } 183 | text { 184 | dominant-baseline: middle; 185 | text-anchor: middle; 186 | font-size: 8pt; 187 | font-family: sans-serif; 188 | fill: #555555; 189 | pointer-events: none; 190 | } 191 | text.asm-count_label { 192 | dominant-baseline: middle; 193 | text-anchor: end; 194 | fill: white; 195 | visibility: hidden; 196 | } 197 | text.asm-length_label { 198 | dominant-baseline: middle; 199 | text-anchor: start; 200 | stroke: none; 201 | fill: #555555; 202 | } 203 | text.asm-assembly_label { 204 | dominant-baseline: middle; 205 | text-anchor: start; 206 | fill: white; 207 | visibility: hidden; 208 | } 209 | text.asm-tl_title { 210 | dominant-baseline: middle; 211 | text-anchor: start; 212 | fill: black; 213 | font-size: 12pt; 214 | } 215 | text.asm-br_title { 216 | dominant-baseline: middle; 217 | text-anchor: start; 218 | fill: black; 219 | font-size: 12pt; 220 | } 221 | text.asm-bl_title { 222 | dominant-baseline: middle; 223 | text-anchor: start; 224 | fill: black; 225 | font-size: 12pt; 226 | } 227 | text.asm-live_title { 228 | dominant-baseline: middle; 229 | text-anchor: start; 230 | fill: black; 231 | font-size: 12pt; 232 | } 233 | text.asm-tr_title { 234 | dominant-baseline: middle; 235 | text-anchor: start; 236 | fill: black; 237 | font-size: 12pt; 238 | } 239 | .asm-key { 240 | dominant-baseline: auto; 241 | text-anchor: start; 242 | fill: #555555; 243 | font-size: 10pt; 244 | } 245 | .asm-right { 246 | text-anchor: end; 247 | } 248 | .assembly_stats { 249 | position:relative; 250 | height:600px; 251 | width: 600px; 252 | } 253 | #asm-scale_form_wrapper { 254 | position: absolute; 255 | text-align: center; 256 | height:100%; 257 | width:100%; 258 | top: 0px; 259 | left:0px; 260 | font-size: 10pt; 261 | font-family: sans-serif; 262 | fill: #555555; 263 | } 264 | #asm-scale_form_bg { 265 | position: relative; 266 | display: inline-block; 267 | height:100%; 268 | width:100%; 269 | background-color: rgba(0, 0, 0, 0.5); 270 | } 271 | #asm-scale_form_div { 272 | padding-top: 50px; 273 | width: 200px; 274 | height: 150px; 275 | position: absolute; 276 | left: 50%; 277 | top: 50%; 278 | margin: -100px 0 0 -100px; 279 | background-color: white; 280 | border-radius: 100px; 281 | } 282 | .asm-form_label:after { 283 | content: " "; 284 | display: block; 285 | clear: both; 286 | } 287 | .asm-form_element { 288 | margin-bottom: 1em; 289 | } 290 | -------------------------------------------------------------------------------- /css/square-plot.css: -------------------------------------------------------------------------------- 1 | .axis text { 2 | font: 20px sans-serif; 3 | fill: #555555; 4 | } 5 | 6 | .axis line, 7 | .axis path { 8 | fill: none; 9 | stroke-width:1px; 10 | stroke: #555555; 11 | shape-rendering: crispEdges; 12 | vector-effect:non-scaling-stroke; 13 | } 14 | 15 | .asm-cumulative-point { 16 | stroke:#555555; 17 | stroke-width:2px; 18 | fill:#ffffff; 19 | pointer-events:none; 20 | } 21 | .asm-cumulative-line { 22 | stroke:#555555; 23 | stroke-width:2px; 24 | fill:none; 25 | } 26 | .asm-reference-line { 27 | stroke:#e31a1c; 28 | stroke-width:2px; 29 | fill:none; 30 | } 31 | path.asm-square-focus { 32 | stroke-width:4px; 33 | } 34 | text.asm-square-focus { 35 | font-weight:bold; 36 | } 37 | .asm-square-key-text { 38 | font-size:16px; 39 | stroke:none; 40 | stroke-width:0px; 41 | fill:#555555; 42 | text-anchor:start; 43 | dominant-baseline:alphabetical; 44 | } 45 | .asm-reference-key text { 46 | stroke:none; 47 | stroke-width:0px; 48 | fill:#e31a1c; 49 | } 50 | .d3-tip { 51 | pointer-events:none; 52 | line-height: 1.2; 53 | font-weight: normal; 54 | font-family:consolas,monospace; 55 | padding: 8px; 56 | background: rgba(0, 0, 0, 0.8); 57 | color: #fff; 58 | border-radius: 4px; 59 | } 60 | 61 | /* Creates a small triangle extender for the tooltip */ 62 | .d3-tip:after { 63 | pointer-events:none; 64 | box-sizing: border-box; 65 | display: inline; 66 | font-size: 10px; 67 | width: 100%; 68 | line-height: 1; 69 | color: rgba(0, 0, 0, 0.8); 70 | content: "\25BC"; 71 | position: absolute; 72 | margin: -2px; 73 | text-align: center; 74 | } 75 | 76 | /* Style northward tooltips differently */ 77 | .d3-tip.n:after { 78 | pointer-events:none; 79 | margin: -2px; 80 | top: 100%; 81 | left: 0; 82 | } 83 | -------------------------------------------------------------------------------- /css/table.css: -------------------------------------------------------------------------------- 1 | table { 2 | font-size: 0.75em; 3 | text-align: right; 4 | margin: 0 auto; 5 | margin-top:20px; 6 | border-spacing:0; 7 | } 8 | tr:nth-child(odd) { 9 | background-color: rgba(166, 206, 227,0.5); 10 | } 11 | tr:nth-child(1) { 12 | background-color: rgba(31, 120, 180,0.5); 13 | color: #000; 14 | } 15 | td { 16 | padding: 4px; 17 | } 18 | -------------------------------------------------------------------------------- /js/circle-plot.js: -------------------------------------------------------------------------------- 1 | function Assembly(stats, scaffolds, contigs) { 2 | this.scaffolds = scaffolds ? scaffolds : stats.scaffolds; 3 | this.contigs = contigs ? contigs : stats.contigs; 4 | this.scaffold_count = stats.scaffold_count ? stats.scaffold_count : stats.scaffolds.length; 5 | this.genome = stats.genome; 6 | this.assembly = stats.assembly; 7 | this.N = stats.N ? stats.N <= 100 ? stats.N < 1 ? stats.N * 100 : stats.N : stats.N / this.assembly * 100 : 0; 8 | this.ATGC = stats.ATGC ? stats.ATGC <= 100 ? stats.ATGC <= 1 ? stats.ATGC * 100 : stats.ATGC : stats.ATGC / this.assembly * 100 : 100 - this.N; 9 | this.GC = stats.GC ? stats.GC <= 100 ? stats.GC <= 1 ? stats.GC * 100 : stats.GC : stats.GC / this.assembly * 100 : 0; 10 | this.contig_sum = this.assembly - this.assembly * this.N / 100; 11 | this.cegma_complete = stats.cegma_complete; 12 | this.cegma_partial = stats.cegma_partial; 13 | this.busco = stats.busco; 14 | this.scaffolds = stats.scaffolds.sort(function(a, b) { 15 | return b - a 16 | }); 17 | var npct_length = {}; 18 | var npct_count = {}; 19 | this.GCs = stats.GCs ? stats.GCs : stats.binned_GCs; 20 | this.Ns = stats.Ns ? stats.Ns : stats.binned_Ns; 21 | 22 | if (stats.binned_scaffold_lengths){ 23 | this.npct_length = stats.binned_scaffold_lengths; 24 | this.npct_count = stats.binned_scaffold_counts; 25 | if (stats.binned_contig_lengths){ 26 | this.nctg_length = stats.binned_contig_lengths; 27 | this.nctg_count = stats.binned_contig_counts; 28 | this.contig_count = stats.contig_count; 29 | } 30 | } 31 | else { 32 | var sum = stats.scaffolds.reduce(function(previousValue, currentValue, index, array) { 33 | return previousValue + currentValue; 34 | }); 35 | if (stats.contigs) { 36 | var ctgsum = stats.contigs.reduce(function(previousValue, currentValue, index, array) { 37 | return previousValue + currentValue; 38 | }); 39 | } 40 | var lsum = 0; 41 | this.scaffolds.forEach(function(length, index, array) { 42 | var new_sum = lsum + length; 43 | if (Math.floor(new_sum / sum * 1000) > Math.floor(lsum / sum * 100)) { 44 | npct_length[Math.floor(new_sum / sum * 1000)] = length; 45 | npct_count[Math.floor(new_sum / sum * 1000)] = index + 1; 46 | } 47 | lsum = new_sum; 48 | }); 49 | this.seq = Array.apply(0, Array(1000)).map(function(x, y) { 50 | return 1000 - y; 51 | }); 52 | this.seq.forEach(function(i, index) { 53 | if (!npct_length[i]) npct_length[i] = npct_length[(i + 1)]; 54 | if (!npct_count[i]) npct_count[i] = npct_count[(i + 1)]; 55 | }); 56 | this.npct_length = $.map(npct_length,function(value,index){return value}); 57 | this.npct_count = $.map(npct_count,function(value,index){return value}); 58 | 59 | var nctg_length = {}; 60 | var nctg_count = {}; 61 | 62 | if (stats.contigs) { 63 | this.contigs = stats.contigs.sort(function(a, b) { 64 | return b - a 65 | }); 66 | 67 | var lsum = 0; 68 | this.contigs.forEach(function(length, index, array) { 69 | var new_sum = lsum + length; 70 | if (Math.floor(new_sum / ctgsum * 1000) > Math.floor(lsum / ctgsum * 100)) { 71 | nctg_length[Math.floor(new_sum / ctgsum * 1000)] = length; 72 | nctg_count[Math.floor(new_sum / ctgsum * 1000)] = index + 1; 73 | } 74 | lsum = new_sum; 75 | }); 76 | this.seq.forEach(function(i, index) { 77 | if (!nctg_length[i]) nctg_length[i] = nctg_length[(i + 1)]; 78 | if (!nctg_count[i]) nctg_count[i] = nctg_count[(i + 1)]; 79 | }); 80 | this.nctg_length = $.map(nctg_length,function(value,index){return value}); 81 | this.nctg_count = $.map(nctg_count,function(value,index){return value}); 82 | this.contig_count = stats.contigs.length; 83 | } 84 | } 85 | this.scale = {}; 86 | this.setScale('percent', 'linear', [0, 100], [180 * (Math.PI / 180), 90 * (Math.PI / 180)]); 87 | this.setScale('100percent', 'linear', [0, 100], [0, 2 * Math.PI]); 88 | this.setScale('gc', 'linear', [0, 100], [0, 100]); // range will be updated when drawing 89 | this.setScale('count', 'log', [1, 1e6], [100, 1]); // range will be updated when drawing 90 | this.setScale('length', 'sqrt', [1, 1e6], [1, 100]); // range will be updated range when drawing 91 | } 92 | 93 | Assembly.prototype.setScale = function(element, scaling, domain, range) { 94 | this.scale[element] = scaling == 'log' ? d3.scale.log() : scaling == 'sqrt' ? d3.scale.sqrt() : d3.scale.linear(); 95 | this.scale[element].domain(domain); 96 | this.scale[element].range(range); 97 | } 98 | 99 | Assembly.prototype.drawPlot = function(parent_div, longest, circle_span) { 100 | 101 | // setup plot dimensions 102 | var size = 600; 103 | var margin = 100; 104 | var tick = 10; 105 | var w = 12; // coloured box size for legend 106 | 107 | this.parent_div = parent_div; 108 | var parent = d3.select('#' + parent_div); 109 | var svg = parent.append('svg'); 110 | 111 | 112 | svg.attr('width', '100%') 113 | .attr('height', '100%') 114 | .attr('viewBox', '0 0 ' + size + ' ' + size) 115 | .attr('preserveAspectRatio', 'xMidYMid meet') 116 | 117 | // setup radii for circular plots 118 | var radii = {}; 119 | radii.core = [0, (size - margin * 2 - tick * 2) / 2]; 120 | radii.core.majorTick = [radii.core[1], radii.core[1] + tick]; 121 | radii.core.minorTick = [radii.core[1], radii.core[1] + tick / 2]; 122 | 123 | radii.percent = [radii.core[1] + tick * 4, radii.core[1]];; 124 | radii.percent.majorTick = [radii.percent[0], radii.percent[0] - tick]; 125 | radii.percent.minorTick = [radii.percent[0], radii.percent[0] - tick / 2]; 126 | 127 | radii.genome = [0, tick * 3];; 128 | 129 | radii.ceg = [0, tick * 2, tick * 4]; 130 | radii.ceg.majorTick = [radii.ceg[2], radii.ceg[2] + tick / 1.5]; 131 | radii.ceg.minorTick = [radii.ceg[2], radii.ceg[2] + tick / 3]; 132 | 133 | this.radii = radii; 134 | 135 | // adjust scales for plot dimensions/data 136 | if (!longest) longest = this.scaffolds[0] + 1 137 | if (longest <= this.scaffolds[0]) longest = this.scaffolds[0] + 1 138 | if (!circle_span) circle_span = this.assembly 139 | if (circle_span < this.assembly) circle_span = this.assembly 140 | var span_ratio = this.assembly / circle_span * 100; 141 | this.scale['length'].domain([1, longest]) 142 | this.scale['length'].range([radii.core[0], radii.core[1]]) 143 | this.scale['count'].range([radii.core[1], radii.core[0] + radii.core[1] / 3]) 144 | this.scale['percent'].range([0, (2 * Math.PI * this.assembly / circle_span)]) 145 | this.scale['gc'].range([radii.percent[1], radii.percent[0]]) 146 | 147 | var lScale = this.scale['length']; 148 | var cScale = this.scale['count']; 149 | var pScale = this.scale['percent']; 150 | var p100Scale = this.scale['100percent']; 151 | var gScale = this.scale['gc']; 152 | var npct_length = this.npct_length; 153 | var npct_count = this.npct_count; 154 | var nctg_length = this.nctg_length; 155 | var nctg_count = this.nctg_count; 156 | var nctg_GC = this.nctg_GC; 157 | var nctg_N = this.nctg_N; 158 | var scaffolds = this.scaffolds; 159 | var contigs = this.contigs; 160 | 161 | // create a group for the plot 162 | var g = svg.append('g') 163 | .attr("transform", "translate(" + size / 2 + "," + size / 2 + ")") 164 | .attr("id", "asm-g-plot"); 165 | 166 | 167 | 168 | 169 | // draw base composition axis fill 170 | var bcg = g.append('g') 171 | .attr("id", "asm-g-base_composition"); 172 | var bcdg = bcg.append('g') 173 | .attr("id", "asm-g-base_composition_data"); 174 | var n = 100 - this.ATGC; 175 | var gc_start = n / 100 * this.GC; 176 | if (this.GCs && this.Ns) { 177 | plot_arc(bcdg, radii.percent[0], radii.percent[1], pScale(0), pScale(100), 'asm-ns'); 178 | var lower = []; 179 | var upper = []; 180 | var GCs = this.GCs; 181 | var Ns = this.Ns; 182 | var GCs_min; 183 | var GCs_max; 184 | if (Ns[0].hasOwnProperty('mean')){ 185 | Ns = Ns.map(function(d){return d.mean}) 186 | GCs_min = GCs.map(function(d){return d.min}) 187 | GCs_max = GCs.map(function(d){return d.max}) 188 | GCs = GCs.map(function(d){return d.mean}) 189 | } 190 | Ns.forEach(function(current, i) { 191 | lower.push((0)); 192 | upper.push((100 - current + lower[i])); 193 | }); 194 | var line = d3.svg.line() 195 | .x(function(d, i) { 196 | return Math.cos(pScale(i / 10) - Math.PI / 2) * (gScale(d)); 197 | }) 198 | .y(function(d, i) { 199 | return Math.sin(pScale(i / 10) - Math.PI / 2) * (gScale(d)); 200 | }); 201 | 202 | var line = d3.svg.line() 203 | .x(function(d, i) { 204 | return Math.cos(pScale(i / 10) - Math.PI / 2) * (gScale(d)); 205 | }) 206 | .y(function(d, i) { 207 | return Math.sin(pScale(i / 10) - Math.PI / 2) * (gScale(d)); 208 | }); 209 | var revline = d3.svg.line() 210 | .x(function(d, i) { 211 | return Math.cos(pScale((1000 - i) / 10) - Math.PI / 2) * (gScale(d)); 212 | }) 213 | .y(function(d, i) { 214 | return Math.sin(pScale((1000 - i) / 10) - Math.PI / 2) * (gScale(d)); 215 | }); 216 | var atgc = line([0]) + 'L' + line(lower).replace(/M[^L]+?/, '') + revline(upper.reverse()).replace('M', 'L') 217 | 218 | bcdg.append("path") 219 | .attr("class", "asm-atgc") 220 | .attr("d", atgc) 221 | .attr("fill-rule", "evenodd"); 222 | var gc = line([0]) + 'L' + line(lower).replace(/M[^L]+?/, '') + revline(GCs.reverse()).replace('M', 'L') 223 | bcdg.append("path") 224 | .attr("class", "asm-gc") 225 | .attr("d", gc) 226 | .attr("fill-rule", "evenodd"); 227 | if (GCs_min){ 228 | var gc_min = revline(GCs_min.reverse()) 229 | bcdg.append("path") 230 | .attr("class", "asm-atgc-line") 231 | .attr("d", gc_min); 232 | var gc_max = revline(GCs_max.reverse()) 233 | bcdg.append("path") 234 | .attr("class", "asm-gc-line") 235 | .attr("d", gc_max); 236 | } 237 | 238 | } else { 239 | plot_arc(bcdg, radii.percent[0], radii.percent[1], pScale(0), pScale(100), 'asm-ns'); 240 | plot_arc(bcdg, radii.percent[0], radii.percent[1], pScale(gc_start), pScale(gc_start + this.ATGC), 'asm-atgc'); 241 | plot_arc(bcdg, radii.percent[0], radii.percent[1], pScale(gc_start), pScale(this.GC), 'asm-gc'); 242 | } 243 | var bcag = bcg.append('g') 244 | .attr("id", "asm-g-base_composition_axis"); 245 | percent_axis(bcag, radii, pScale); 246 | 247 | // plot BUSCO/CEGMA completeness if available 248 | if (this.busco) { 249 | var ccg = g.append('g') 250 | .attr('transform', 'translate(' + (radii.percent[1] + tick * 3.5) + ',' + (-radii.percent[1] - tick * 0) + ')') 251 | .attr("id", "asm-busco_completeness"); 252 | var ccdg = ccg.append('g') 253 | .attr("id", "asm-busco_completeness_data"); 254 | plot_arc(ccdg, radii.ceg[1]/1.5, radii.ceg[2], p100Scale(this.busco.C), p100Scale(this.busco.C+this.busco.F), 'asm-busco_F'); 255 | plot_arc(ccdg, radii.ceg[1]/1.5, radii.ceg[2], p100Scale(0), p100Scale(this.busco.C), 'asm-busco_C'); 256 | plot_arc(ccdg, radii.ceg[1]/1.5, radii.ceg[2], p100Scale(0), p100Scale(this.busco.D), 'asm-busco_D'); 257 | var ccag = ccg.append('g') 258 | .attr("id", "asm-busco_completeness_axis"); 259 | ccag.append('circle').attr('r', radii.ceg[1]/1.5).attr('class', 'asm-axis'); 260 | ccag.append('line').attr('y1', -radii.ceg[1]/1.5).attr('y2', -radii.ceg[2]).attr('class', 'asm-axis'); 261 | cegma_axis(ccag, radii, p100Scale); 262 | } 263 | else if (this.cegma_complete) { 264 | var ccg = g.append('g') 265 | .attr('transform', 'translate(' + (radii.percent[1] + tick * 3) + ',' + (-radii.percent[1] - tick * 2) + ')') 266 | .attr("id", "asm-cegma_completeness"); 267 | var ccdg = ccg.append('g') 268 | .attr("id", "asm-cegma_completeness_data"); 269 | plot_arc(ccdg, radii.ceg[0], radii.ceg[1], p100Scale(0), p100Scale(this.cegma_complete), 'asm-ceg_comp'); 270 | plot_arc(ccdg, radii.ceg[1], radii.ceg[2], p100Scale(0), p100Scale(this.cegma_partial), 'asm-ceg_part'); 271 | var ccag = ccg.append('g') 272 | .attr("id", "asm-cegma_completeness_axis"); 273 | ccag.append('circle').attr('r', radii.ceg[1]).attr('class', 'asm-ceg_line'); 274 | ccag.append('line').attr('y2', -radii.ceg[2]).attr('class', 'asm-axis'); 275 | cegma_axis(ccag, radii, p100Scale); 276 | } 277 | 278 | var line = d3.svg.line() 279 | .x(function(d, i) { 280 | return Math.cos(pScale(i / 10) - Math.PI / 2) * (radii.core[1] - cScale(d)); 281 | }) 282 | .y(function(d, i) { 283 | return Math.sin(pScale(i / 10) - Math.PI / 2) * (radii.core[1] - cScale(d)); 284 | }); 285 | 286 | //plot contig count data if available 287 | if (this.contigs) { 288 | var ctcg = g.append('g') 289 | .attr("id", "asm-g-contig_count"); 290 | var ctcdg = ctcg.append('g') 291 | .attr("id", "asm-g-contig_count_data"); 292 | var ctg_counts = $.map(this.nctg_count, function(value, index) { 293 | return [value]; 294 | }); 295 | ctcdg.append("path") 296 | .datum(ctg_counts) 297 | .attr("class", "asm-contig_count asm-remote") 298 | .attr("d", line); 299 | } 300 | //plot scaffold count data 301 | var scg = g.append('g') 302 | .attr("id", "asm-g-scaffold_count"); 303 | var scdg = scg.append('g') 304 | .attr("id", "asm-g-scaffold_count_data"); 305 | var scaf_counts = $.map(this.npct_count, function(value, index) { 306 | return [value]; 307 | }); 308 | scdg.append("path") 309 | .datum(scaf_counts) 310 | .attr("class", "asm-count asm-remote") 311 | .attr("d", line); 312 | 313 | 314 | // plot scaffold lengths 315 | var slg = g.append('g') 316 | .attr("id", "asm-g-scaffold_length"); 317 | var sldg = slg.append('g') 318 | .attr("id", "asm-g-scaffold_length_data"); 319 | 320 | var line = d3.svg.line() 321 | .x(function(d, i) { 322 | return Math.cos(pScale(i / 10) - Math.PI / 2) * (radii.core[1] - lScale(d)); 323 | }) 324 | .y(function(d, i) { 325 | return Math.sin(pScale(i / 10) - Math.PI / 2) * (radii.core[1] - lScale(d)); 326 | }); 327 | var revline = d3.svg.line() 328 | .x(function(d, i) { 329 | return Math.cos(pScale((1000 - i) / 10) - Math.PI / 2) * (radii.core[1] - lScale(d)); 330 | }) 331 | .y(function(d, i) { 332 | return Math.sin(pScale((1000 - i) / 10) - Math.PI / 2) * (radii.core[1] - lScale(d)); 333 | }); 334 | var scaf_lengths = $.map(this.npct_length, function(value, index) { 335 | return [value]; 336 | }); 337 | var zeros = Array.apply(0, Array(1000)).map(function(x, y) { 338 | return 0; 339 | }); 340 | var hollow = line([0]) + 'L' + line(scaf_lengths).replace(/M[^L]+?/, '') + revline(zeros).replace('M', 'L') 341 | sldg.append("path") 342 | .attr("class", "asm-pie") 343 | .attr("d", hollow) 344 | .attr("fill-rule", "oddeven"); 345 | 346 | 347 | // plot contig lengths if available 348 | if (this.contigs) { 349 | var clg = g.append('g') 350 | .attr("id", "asm-g-contig_length"); 351 | var cldg = slg.append('g') 352 | .attr("id", "asm-g-contig_length_data"); 353 | var ctg_lengths = $.map(this.nctg_length, function(value, index) { 354 | return [value]; 355 | }); 356 | var hollow = line([0]) + 'L' + line(ctg_lengths).replace(/M[^L]+?/, '') + revline(zeros).replace('M', 'L') 357 | sldg.append("path") 358 | .attr("class", "asm-contig") 359 | .attr("d", hollow) 360 | .attr("fill-rule", "evenodd"); 361 | } 362 | // highlight n50, n90 and longest scaffold 363 | var slhg = slg.append('g') 364 | .attr("id", "asm-g-scaffold_length_highlight"); 365 | var long_pct = scaffolds[0] / this.assembly * 100; 366 | if (long_pct >= 0.1) { 367 | plot_arc(slhg, radii.core[1] - lScale(scaffolds[0]), radii.core[1], 0, pScale(long_pct), 'asm-longest_pie'); 368 | } 369 | plot_arc(slhg, radii.core[1] - lScale(npct_length[500]), radii.core[1], 0, pScale(50), 'asm-n50_pie'); 370 | plot_arc(slhg, radii.core[1] - lScale(npct_length[900]), radii.core[1], 0, pScale(90), 'asm-n90_pie'); 371 | plot_arc(slhg, radii.core[1] - lScale(npct_length[500]), radii.core[1], pScale(50), pScale(50), 'asm-n50_pie asm-highlight'); 372 | if (long_pct >= 0.1) { 373 | plot_arc(slhg, radii.core[1] - lScale(scaffolds[0]), radii.core[1], pScale(long_pct), pScale(long_pct), 'asm-longest_pie asm-highlight'); 374 | } 375 | 376 | // add gridlines at powers of 10 377 | var length_seq = []; 378 | var power = 2; 379 | while (Math.pow(10, power) <= longest) { 380 | length_seq.push(power) 381 | power++; 382 | } 383 | var slgg = slg.append('g') 384 | .attr("id", "asm-g-scaffold_length_gridlines"); 385 | length_seq.forEach(function(i, index) { 386 | //if(Math.pow(10,i+4) > longest && Math.pow(10,i+1) > npct_length[1000]){ 387 | if (Math.pow(10, i + 4) >= longest && Math.pow(10, i + 1) > npct_length[900] && Math.pow(10, i) < npct_length[100]) { 388 | //plot_arc(slgg,radii.core[1]-lScale(Math.pow(10,i)),radii.core[1]-lScale(Math.pow(10,i)),pScale(0),pScale(100),'asm-length_axis asm-dashed'); 389 | slgg.append('circle') 390 | .attr('r', radii.core[1] - lScale(Math.pow(10, i))) 391 | .attr('cx', 0) 392 | .attr('cy', 0) 393 | .attr('stroke-dasharray', '10,10') 394 | .attr('class', 'asm-length_axis'); 395 | } 396 | }); 397 | 398 | // plot scaffold/contig count gridlines 399 | if (!this.contigs) { 400 | var scgg = scg.append('g') 401 | .attr("id", "asm-g-scaffold_count_gridlines"); 402 | [1, 2, 3, 4, 5, 6, 7].forEach(function(i, index) { 403 | scgg.append('circle') 404 | .attr('class', 'asm-count_axis') 405 | .attr('r', (radii.core[1] - cScale(Math.pow(10, i)))) 406 | }); 407 | } else { 408 | var ctcgg = scg.append('g') 409 | .attr("id", "asm-g-contig_count_gridlines"); 410 | [1, 2, 3, 4, 5, 6, 7].forEach(function(i, index) { 411 | ctcgg.append('circle') 412 | .attr('class', 'asm-count_axis') 413 | .attr('r', (radii.core[1] - cScale(Math.pow(10, i)))) 414 | }); 415 | } 416 | 417 | 418 | // plot radial axis 419 | var mag = g.append('g') 420 | .attr("id", "asm-g-main_axis"); 421 | var slag = g.append('g') 422 | .attr("id", "asm-g-scaffold_length_axis"); 423 | 424 | length_seq.forEach(function(i, index) { 425 | if (Math.pow(10, i + 4) >= longest && Math.pow(10, i + 1) > npct_length[900] && Math.pow(10, i) < npct_length[100]) { 426 | slag.append('text') 427 | .attr('transform', 'translate(' + (Math.pow(1.5, i) + 2) + ',' + (-radii.core[1] + lScale(Math.pow(10, i)) + 4) + ')') 428 | .text(getReadableSeqSizeString(Math.pow(10, i), 0)) 429 | .attr('class', 'asm-length_label'); 430 | 431 | } 432 | slag.append('line') 433 | .attr('x1', 0) 434 | .attr('y1', -radii.core[1] + lScale(Math.pow(10, i))) 435 | .attr('x2', Math.pow(1.5, i)) 436 | .attr('y2', -radii.core[1] + lScale(Math.pow(10, i))) 437 | .attr('class', 'asm-majorTick'); 438 | }); 439 | slag.append('line') 440 | .attr("class", "asm-length asm-axis") 441 | .attr('x1', 0) 442 | .attr('y1', -radii.core[1]) 443 | .attr('x2', 0) 444 | .attr('y2', 0) 445 | 446 | // draw circumferential axis 447 | circumference_axis(mag, radii, pScale); 448 | 449 | // draw legends 450 | var lg = g.append('g') 451 | .attr("id", "asm-g-legend"); 452 | 453 | // draw BUSCO/CEGMA legend 454 | if (this.busco) { 455 | var lccg = lg.append('g') 456 | .attr("id", "asm-g-busco_completeness_legend"); 457 | var txt = lccg.append('text') 458 | .attr('transform', 'translate(' + (size / 2 - 210) + ',' + (-size / 2 + 20) + ')') 459 | .attr('class', 'asm-tr_title'); 460 | txt.append('tspan').text('BUSCO (n = ' + this.busco.n.toLocaleString() + ')'); 461 | var key = lccg.append('g').attr('transform', 'translate(' + (size / 2 - 210) + ',' + (-size / 2 + 28) + ')'); 462 | key.append('rect').attr('height', w).attr('width', w).attr('class', 'asm-busco_C asm-toggle'); 463 | key.append('text').attr('x', w + 3).attr('y', w - 1).text('Comp. (' + this.busco.C.toFixed(1) + '%)').attr('class', 'asm-key'); 464 | key.append('rect').attr('y', w * 1.5).attr('height', w).attr('width', w).attr('class', 'asm-busco_D asm-toggle'); 465 | key.append('text').attr('x', w + 3).attr('y', w * 2.5 - 1).text('Dup. (' + this.busco.D.toFixed(1) + '%)').attr('class', 'asm-key'); 466 | key.append('rect').attr('y', w * 3).attr('height', w).attr('width', w).attr('class', 'asm-busco_F asm-toggle'); 467 | key.append('text').attr('x', w + 3).attr('y', w * 4 - 1).text('Frag. (' + this.busco.F.toFixed(1) + '%)').attr('class', 'asm-key'); 468 | } 469 | else if (this.cegma_complete) { 470 | var lccg = lg.append('g') 471 | .attr("id", "asm-g-cegma_completeness_legend"); 472 | var txt = lccg.append('text') 473 | .attr('transform', 'translate(' + (size / 2 - 230) + ',' + (-size / 2 + 20) + ')') 474 | .attr('class', 'asm-tr_title'); 475 | txt.append('tspan').text('CEGMA completeness'); 476 | var key = lccg.append('g').attr('transform', 'translate(' + (size / 2 - 230) + ',' + (-size / 2 + 28) + ')'); 477 | key.append('rect').attr('height', w).attr('width', w).attr('class', 'asm-ceg_comp asm-toggle'); 478 | key.append('text').attr('x', w + 3).attr('y', w - 1).text('Complete (' + this.cegma_complete.toFixed(1) + '%)').attr('class', 'asm-key'); 479 | key.append('rect').attr('y', w * 1.5).attr('height', w).attr('width', w).attr('class', 'asm-ceg_part asm-toggle'); 480 | key.append('text').attr('x', w + 3).attr('y', w * 2.5 - 1).text('Partial (' + this.cegma_partial.toFixed(1) + '%)').attr('class', 'asm-key'); 481 | } 482 | 483 | //draw base composition legend 484 | var lbcg = lg.append('g') 485 | .attr("id", "asm-g-base_composition_legend"); 486 | var txt = lbcg.append('text') 487 | .attr('transform', 'translate(' + (size / 2 - 140) + ',' + (size / 2 - 110) + ')') 488 | .attr('class', 'asm-br_title'); 489 | txt.append('tspan').text('Assembly'); 490 | txt.append('tspan').text('base composition').attr('x', 0).attr('dy', 18); 491 | var key = lbcg.append('g').attr('transform', 'translate(' + (size / 2 - 140) + ',' + (size / 2 - 83) + ')'); 492 | var at_text = 'AT (' + (this.ATGC - this.GC).toFixed(1) + '%)'; 493 | var gc_text = 'GC (' + this.GC.toFixed(1) + '%)'; 494 | var n_text = 'N (' + n.toFixed(1) + '%)'; 495 | key.append('rect').attr('height', w).attr('width', w).attr('class', 'asm-gc asm-toggle'); 496 | key.append('text').attr('x', w + 2).attr('y', w - 1).text(gc_text).attr('class', 'asm-key').attr('id','asm-gc_value'); 497 | key.append('rect').attr('y', w * 1.5).attr('height', w).attr('width', w).attr('class', 'asm-atgc asm-toggle'); 498 | key.append('text').attr('x', w + 2).attr('y', w * 2.5 - 1).text(at_text).attr('class', 'asm-key').attr('id','asm-at_value'); 499 | key.append('rect').attr('y', w * 3).attr('height', w).attr('width', w).attr('class', 'asm-ns asm-toggle'); 500 | key.append('text').attr('x', w + 2).attr('y', w * 4 - 1).text(n_text).attr('class', 'asm-key').attr('id','asm-n_value'); 501 | 502 | 503 | //draw scaffold legend 504 | var lsg = lg.append('g') 505 | .attr("id", "asm-g-scaffold_legend"); 506 | var txt = lsg.append('text') 507 | .attr('transform', 'translate(' + (-size / 2 + 10) + ',' + (-size / 2 + 20) + ')') 508 | .attr('class', 'asm-tl_title'); 509 | txt.append('tspan').text('Scaffold statistics'); 510 | //txt.append('tspan').text('distribution').attr('x',0).attr('dy',20); 511 | 512 | var key = lsg.append('g').attr('transform', 'translate(' + (-size / 2 + 10) + ',' + (-size / 2 + 28) + ')'); 513 | key.append('rect').attr('height', w).attr('width', w).attr('class', 'asm-count asm-toggle'); 514 | var count_txt = key.append('text').attr('x', w + 3).attr('y', w - 1).attr('class', 'asm-key') 515 | count_txt.append('tspan').text('Log') 516 | count_txt.append('tspan').attr('baseline-shift', 'sub').attr('font-size', '75%').text(10) 517 | count_txt.append('tspan').text(' scaffold count (total ' + this.scaffold_count.toLocaleString() + ')'); 518 | key.append('rect').attr('y', w * 1.5).attr('height', w).attr('width', w).attr('class', 'asm-pie asm-toggle'); 519 | key.append('text').attr('x', w + 3).attr('y', w * 2.5 - 1).text('Scaffold length (total ' + getReadableSeqSizeString(this.assembly, 0) + ')').attr('class', 'asm-key'); 520 | 521 | 522 | key.append('rect').attr('y', w * 3).attr('height', w).attr('width', w).attr('class', 'asm-longest_pie asm-toggle'); 523 | key.append('text').attr('x', w + 3).attr('y', w * 4 - 1).text('Longest scaffold (' + getReadableSeqSizeString(this.scaffolds[0]) + ')').attr('class', 'asm-key'); 524 | key.append('rect').attr('y', w * 4.5).attr('height', w).attr('width', w).attr('class', 'asm-n50_pie asm-toggle'); 525 | key.append('text').attr('x', w + 3).attr('y', w * 5.5 - 1).text('N50 length (' + getReadableSeqSizeString(this.npct_length[499]) + ')').attr('class', 'asm-key'); 526 | key.append('rect').attr('y', w * 6).attr('height', w).attr('width', w).attr('class', 'asm-n90_pie asm-toggle'); 527 | key.append('text').attr('x', w + 3).attr('y', w * 7 - 1).text('N90 length (' + getReadableSeqSizeString(this.npct_length[899]) + ')').attr('class', 'asm-key'); 528 | 529 | //draw contig legend if available 530 | if (this.contigs) { 531 | var lctg = lg.append('g') 532 | .attr("id", "asm-g-contig_legend"); 533 | var txt = lctg.append('text') 534 | .attr('transform', 'translate(' + (-size / 2 + 10) + ',' + (size / 2 - 70) + ')') 535 | .attr('class', 'asm-bl_title'); 536 | txt.append('tspan').text('Contig statistics'); 537 | 538 | var key = lctg.append('g').attr('transform', 'translate(' + (-size / 2 + 10) + ',' + (size / 2 - 62) + ')'); 539 | key.append('rect').attr('height', w).attr('width', w).attr('class', 'asm-contig_count asm-toggle'); 540 | var count_txt = key.append('text').attr('x', w + 2).attr('y', w - 1).attr('class', 'asm-key') 541 | count_txt.append('tspan').text('Log') 542 | count_txt.append('tspan').attr('baseline-shift', 'sub').attr('font-size', '75%').text(10) 543 | count_txt.append('tspan').text(' contig count (total ' + this.contig_count.toLocaleString() + ')'); 544 | key.append('rect').attr('y', w * 1.5).attr('height', w).attr('width', w).attr('class', 'asm-contig asm-toggle'); 545 | key.append('text').attr('x', w + 3).attr('y', w * 2.5 - 1).text('Contig length (total ' + getReadableSeqSizeString(this.contig_sum, 0) + ')').attr('class', 'asm-key'); 546 | } 547 | 548 | // add adjustable scale legend 549 | var lscl = lg.append('g') 550 | .attr("id", "asm-g-scale_legend"); 551 | var txt = lscl.append('text') 552 | .attr('transform', 'translate(' + (-size / 2 + 10) + ',' + (size / 2 - 150) + ')') 553 | .attr('class', 'asm-bl_title'); 554 | txt.append('tspan').text('Scale'); 555 | 556 | var key = lscl.append('g').attr('transform', 'translate(' + (-size / 2 + 10) + ',' + (size / 2 - 142) + ')'); 557 | var circ_key = key.append('g').attr('width', '100px').attr('height', '14px').attr('transform', 'translate(0,8)').attr('id', 'asm-circ_scale_g'); 558 | var circ_scale_rect = circ_key.append('rect').attr('x', w + 5).attr('y', -3).attr('width', '80px').attr('height', '18px').attr('class', 'asm-scale_rect'); 559 | circ_key.append('circle').attr('cx', w / 2).attr('cy', w / 2).attr('r', w / 2).attr('class', 'asm-axis'); 560 | circ_key.append('line').attr('x1', w / 2).attr('y1', 0).attr('x2', w / 2).attr('y2', w / 2).attr('class', 'asm-axis asm-narrow'); 561 | var readable_circle_span = getReadableSeqSizeString(circle_span, 1) 562 | circ_key.append('text').attr('x', w + 8).attr('y', w - 1).text(readable_circle_span).attr('class', 'asm-key') 563 | var rad_key = key.append('g').attr('width', '100px').attr('height', '14px').attr('transform', 'translate(0,' + (w * 2.5) + ')').attr('id', 'asm-rad_scale_g'); 564 | var rad_scale_rect = rad_key.append('rect').attr('x', w + 5).attr('y', -3).attr('width', '80px').attr('height', '18px').attr('class', 'asm-scale_rect'); 565 | rad_key.append('circle').attr('cx', w / 2).attr('cy', w / 2).attr('r', w / 2).attr('class', 'asm-axis asm-narrow'); 566 | rad_key.append('line').attr('x1', w / 2).attr('y1', 0).attr('x2', w / 2).attr('y2', w / 2).attr('class', 'asm-axis'); 567 | var readable_longest = getReadableSeqSizeString(longest, 1); 568 | rad_key.append('text').attr('x', w + 8).attr('y', w - 1).text(readable_longest).attr('class', 'asm-key'); 569 | 570 | // setup form 571 | var form_div_wrapper = parent.append('div').attr('id', 'asm-scale_form_wrapper').attr('class', 'hidden'); 572 | var form_div_bg = form_div_wrapper.append('div').attr('id', 'asm-scale_form_bg'); 573 | var form_div = form_div_bg.append('div').attr('id', 'asm-scale_form_div') 574 | var form = form_div.append('form').attr('id', 'asm-scale_form') 575 | form.append('label').attr('for', 'asm-circ_scale_input').text('circumference scale:').attr('class', 'asm-form_label') 576 | form.append('input').attr('type', 'text').property('value', readable_circle_span).attr('placeholder', readable_circle_span).attr('id', 'asm-circ_scale_input').attr('class', 'asm-form_element') 577 | form.append('br') 578 | form.append('label').attr('for', 'asm-rad_scale_input').text('radial scale:').attr('class', 'asm-form_label') 579 | form.append('input').attr('type', 'text').property('value', readable_longest).attr('placeholder', readable_longest).attr('id', 'asm-rad_scale_input').attr('class', 'asm-form_element') 580 | form.append('br') 581 | form.append('input').attr('type', 'submit').attr('class', 'asm-form_element') 582 | var asm = this; 583 | $('#'+parent_div+' #asm-scale_form').submit(function(e) { 584 | e.preventDefault(); 585 | var circ_val = toInt($('#'+parent_div+' #asm-circ_scale_input').val()); 586 | var rad_val = toInt($('#'+parent_div+' #asm-rad_scale_input').val()); 587 | asm.reDrawPlot(parent, rad_val, circ_val); 588 | }) 589 | 590 | // hide form 591 | form_div_wrapper.on('click', function() { 592 | form_div_wrapper.classed('hidden', true) 593 | }); 594 | form_div.on('click', function() { 595 | d3.event.stopPropagation(); 596 | }); 597 | 598 | // toggle form visibility 599 | // TODO - fix bug with position in screen coords 600 | d3.selectAll('#'+parent_div+' .asm-scale_rect').on('click', function() { 601 | form_div_wrapper.classed('hidden', !form_div_wrapper.classed('hidden')) 602 | var rect = svg.node().getBoundingClientRect(); 603 | form_div_wrapper.style('height', rect.height) 604 | form_div_wrapper.style('width', rect.width) 605 | 606 | form_div_bg.style('height', rect.height > rect.width ? rect.width : rect.height) 607 | form_div_bg.style('width', rect.height > rect.width ? rect.width : rect.height) 608 | 609 | }); 610 | 611 | // toggle plot features 612 | $('#'+parent_div+' .asm-toggle').on('click', function() { 613 | var button = this; 614 | var classNames = $(this).attr("class").toString().split(' '); 615 | if ($(button).css('fill') != "rgb(255, 255, 255)" && $(button).css('fill') != "#ffffff") { 616 | $(button).css({ 617 | fill: "rgb(255, 255, 255)" 618 | }); 619 | $.each(classNames, function(i, className) { 620 | if (className != 'asm-toggle') { 621 | $('#'+parent_div+' .' + className).each(function() { 622 | if (this != button) { 623 | $(this).css({ 624 | visibility: "hidden" 625 | }) 626 | } 627 | }); 628 | } 629 | }); 630 | } else { 631 | var stroke = $(button).css("stroke"); 632 | $(button).css({ 633 | fill: stroke 634 | }); 635 | $.each(classNames, function(i, className) { 636 | if (className != 'asm-toggle') { 637 | $('#'+parent_div+' .' + className).each(function() { 638 | if (this != button) { 639 | $(this).css({ 640 | visibility: "visible" 641 | }) 642 | } 643 | }); 644 | } 645 | /*if (className == 'asm-count') { 646 | $('#'+parent_div+' .asm-contig_count.asm-toggle').css({ 647 | fill: "rgb(255, 255, 255)" 648 | }) 649 | $('#'+parent_div+' .asm-contig_count.asm-remote').css({ 650 | visibility: "hidden" 651 | }) 652 | } 653 | if (className == 'asm-contig_count') { 654 | $('#'+parent_div+' .asm-count.asm-toggle').css({ 655 | fill: "rgb(255, 255, 255)" 656 | }) 657 | $('#'+parent_div+' .asm-count.asm-remote').css({ 658 | visibility: "hidden" 659 | }) 660 | }*/ 661 | }); 662 | } 663 | }); 664 | 665 | 666 | // show stats for any N value on mouseover 667 | var overlay = g.append('g'); 668 | var path = overlay.append('path'); 669 | var overoverlay = overlay.append('g'); 670 | var output = overlay.append('g').attr('transform', 'translate(' + (size / 2 - 142) + ',' + (size / 2 - 128) + ')'); 671 | var output_rect = output.append('rect').attr('class', 'asm-live_stats hidden').attr('height', 110).attr('width', 150); 672 | var output_text = output.append('g').attr('transform', 'translate(' + (2) + ',' + (18) + ')').attr('class', 'hidden'); 673 | // var output_gc = output.append('g').attr('transform', 'translate(' + (17) + ',' + (18) + ')').attr('class', 'hidden'); 674 | var gc_circle = overoverlay.append('circle').attr('r', radii.percent[0]).attr('fill', 'white').style('opacity', 0); 675 | var stat_circle = overoverlay.append('circle').attr('r', radii.core[1]).attr('fill', 'white').style('opacity', 0); 676 | stat_circle.on('mousemove', function() { 677 | output_rect.classed('hidden', false); 678 | output_text.classed('hidden', false); 679 | path.classed('hidden', false); 680 | output_text.selectAll('text').remove(); 681 | 682 | 683 | var point = d3.mouse(this); 684 | var angle = (50.5 + 50 / Math.PI * Math.atan2(-point[0], point[1])).toFixed(0); 685 | angle = Math.floor(angle * p100Scale(100) / pScale(100) + 0.1) 686 | 687 | if (angle <= 100) { 688 | var arc = d3.svg.arc() 689 | .innerRadius(radii.core[1]) 690 | .outerRadius(radii.core[0]) 691 | .startAngle(pScale(angle - 1)) 692 | .endAngle(pScale(angle)); 693 | path 694 | .attr('d', arc) 695 | .attr('class', 'asm-live_segment'); 696 | 697 | 698 | var txt = output_text.append('text') 699 | .attr('class', 'asm-live_title'); 700 | txt.append('tspan').text('N' + angle); 701 | output_text.append('text').attr('y', 18).text(npct_count[(angle * 10)-1].toLocaleString() + ' scaffolds').attr('class', 'asm-key'); 702 | output_text.append('text').attr('x', 120).attr('y', w * 1.2 + 18).text('>= ' + getReadableSeqSizeString(npct_length[(angle * 10)-1])).attr('class', 'asm-key asm-right'); 703 | if (nctg_length) { 704 | output_text.append('text').attr('y', w * 3 + 18).text(nctg_count[(angle * 10)-1].toLocaleString() + ' contigs').attr('class', 'asm-key'); 705 | output_text.append('text').attr('x', 120).attr('y', w * 4.2 + 18).text('>= ' + getReadableSeqSizeString(nctg_length[(angle * 10)-1])).attr('class', 'asm-key asm-right'); 706 | } 707 | } else { 708 | output_rect.classed('hidden', true); 709 | output_text.classed('hidden', true); 710 | path.classed('hidden', true); 711 | } 712 | }); 713 | stat_circle.on('mouseout', function() { 714 | output_rect.classed('hidden', true); 715 | output_text.classed('hidden', true); 716 | path.classed('hidden', true); 717 | }); 718 | 719 | // update gc content stats on mouseover 720 | if (typeof this.GCs != 'undefined' && this.GCs instanceof Array){ 721 | var GCs = this.GCs; 722 | var Ns = this.Ns; 723 | if (Ns[0].hasOwnProperty('mean')){ 724 | Ns = Ns.map(function(d){return d.mean}); 725 | GCs = GCs.map(function(d){return d.mean}); 726 | } 727 | var slow_plot; 728 | // var sgcg = output_gc.append('g') 729 | // .attr('transform', 'translate(' + (radii.ceg[2] + tick * 1) + ',' + (radii.ceg[2] + tick * 1) + ')') 730 | // .attr("id", "asm-segment_gc"); 731 | // var sgcdg = sgcg.append('g') 732 | // .attr("id", "asm-segment_gc_data"); 733 | // var sgcag = sgcg.append('g') 734 | // .attr("id", "asm-segment_gc_axis"); 735 | //ccag.append('circle').attr('r', radii.ceg[1]).attr('class', 'asm-ceg_line'); 736 | //ccag.append('line').attr('y2', -radii.ceg[2]).attr('class', 'asm-axis'); 737 | // cegma_axis(sgcag, radii, p100Scale); 738 | 739 | gc_circle.on('mousemove', function() { 740 | clearTimeout(slow_plot); 741 | // output_rect.classed('hidden', false); 742 | // output_text.classed('hidden', false); 743 | // output_gc.classed('hidden', false); 744 | path.classed('hidden', false); 745 | // output_text.selectAll('text').remove(); 746 | 747 | 748 | var point = d3.mouse(this); 749 | var angle = (50.5 + 50 / Math.PI * Math.atan2(-point[0], point[1])).toFixed(0); 750 | angle = Math.floor(angle * p100Scale(100) / pScale(100) + 0.1) 751 | 752 | if (angle <= 100) { 753 | slow_plot = setTimeout(function(){ 754 | 755 | var arc = d3.svg.arc() 756 | .innerRadius(radii.core[0]) 757 | .outerRadius(radii.percent[0]) 758 | .startAngle(pScale(angle - 1)) 759 | .endAngle(pScale(angle)); 760 | path 761 | .attr('d', arc) 762 | .attr('class', 'asm-live_segment'); 763 | 764 | 765 | var txt = output_text.append('text') 766 | .attr('class', 'asm-live_title'); 767 | txt.append('tspan').text((angle - 1) + '-' + angle + '%'); 768 | 769 | // plot segment percentages as pie 770 | var seg_n = Ns.slice((angle-1) * 10,angle*10).reduce(function(a, b) { return a + b; }, 0)/10; 771 | var seg_gc = GCs.slice((angle-1) * 10,angle*10).reduce(function(a, b) { return a + b; }, 0)/10; 772 | var seg_gc_start = seg_n / 100 * seg_gc; 773 | 774 | $('#'+parent_div+' #asm-at_value').text('AT (' + (100 - seg_gc).toFixed(1) + '%)'); 775 | $('#'+parent_div+' #asm-gc_value').text('GC (' + seg_gc.toFixed(1) + '%)'); 776 | $('#'+parent_div+' #asm-n_value').text('N (' + seg_n.toFixed(1) + '%)'); 777 | //plot_arc(sgcdg, radii.ceg[1]/1.5, radii.ceg[2], p100Scale(0), p100Scale(100), 'asm-ns'); 778 | //plot_arc(sgcdg, radii.ceg[1]/1.5, radii.ceg[2], p100Scale(seg_gc_start), p100Scale(seg_gc_start + (100 - seg_n)), 'asm-atgc'); 779 | //plot_arc(sgcdg, radii.ceg[1]/1.5, radii.ceg[2], p100Scale(seg_gc_start), p100Scale(seg_gc), 'asm-gc'); 780 | 781 | //sgcdg.append('circle').attr('r', radii.ceg[1]/1.5).attr('class', 'asm-axis'); 782 | }) 783 | 784 | } else { 785 | clearTimeout(slow_plot); 786 | $('#'+parent_div+' #asm-at_value').text(at_text); 787 | $('#'+parent_div+' #asm-gc_value').text(gc_text); 788 | $('#'+parent_div+' #asm-n_value').text(n_text); 789 | path.classed('hidden', true); 790 | } 791 | }); 792 | gc_circle.on('mouseout', function() { 793 | clearTimeout(slow_plot); 794 | $('#'+parent_div+' #asm-at_value').text(at_text); 795 | $('#'+parent_div+' #asm-gc_value').text(gc_text); 796 | $('#'+parent_div+' #asm-n_value').text(n_text); 797 | path.classed('hidden', true); 798 | }); 799 | } 800 | } 801 | 802 | Assembly.prototype.toggleVisible = function(css_class_array) { 803 | var parent_div = this.parent_div; 804 | css_class_array.forEach(function(css_class){ 805 | $('#' + parent_div + ' .' + css_class + '.asm-toggle').trigger('click'); 806 | }); 807 | } 808 | 809 | Assembly.prototype.reDrawPlot = function(parent, longest, circle_span) { 810 | parent.html(''); 811 | this.drawPlot(parent.attr('id'), longest, circle_span); 812 | } 813 | 814 | function circumference_axis(parent, radii, scale) { 815 | var g = parent.append('g'); 816 | var axis = d3.svg.arc() 817 | .innerRadius(radii.core[1]) 818 | .outerRadius(radii.core[1]) 819 | .startAngle(scale(0)) 820 | .endAngle(scale(100)); 821 | g.append('path') 822 | .attr('d', axis) 823 | .attr('class', 'asm-axis'); 824 | var seq = Array.apply(0, Array(50)).map(function(x, y) { 825 | return y * 2; 826 | }); 827 | seq.forEach(function(i, index) { 828 | var tick = d3.svg.arc() 829 | .innerRadius(radii.core.minorTick[0]) 830 | .outerRadius(radii.core.minorTick[1]) 831 | .startAngle(scale(i)) 832 | .endAngle(scale(i)); 833 | g.append('path') 834 | .attr('d', tick) 835 | .attr('class', 'asm-minorTick'); 836 | }); 837 | var seq = Array.apply(0, Array(11)).map(function(x, y) { 838 | return y * 10; 839 | }); 840 | seq.forEach(function(i, index) { 841 | var tick = d3.svg.arc() 842 | .innerRadius(radii.core.majorTick[0]) 843 | .outerRadius(radii.core.majorTick[1]) 844 | .startAngle(scale(i)) 845 | .endAngle(scale(i)); 846 | g.append('path') 847 | .attr('d', tick) 848 | .attr('class', 'asm-majorTick'); 849 | var x = Math.cos(scale(i) - Math.PI / 2) * (radii.core.majorTick[1] + 10); 850 | var y = Math.sin(scale(i) - Math.PI / 2) * (radii.core.majorTick[1] + 10); 851 | g.append('text') 852 | .text(function() { 853 | return index > 0 ? (index == 10 && scale(100) < 1.96 * Math.PI) ? '100%' : index < 10 ? index * 10 : '' : '0%' 854 | }) 855 | .attr('transform', 'translate(' + x + ',' + y + ') rotate(' + scale(i) / (Math.PI / 180) + ')'); 856 | }); 857 | } 858 | 859 | 860 | function percent_axis(parent, radii, scale) { 861 | var g = parent.append('g'); 862 | var axis = d3.svg.arc() 863 | .innerRadius(radii.percent[0]) 864 | .outerRadius(radii.percent[0]) 865 | .startAngle(scale(0)) 866 | .endAngle(scale(100)); 867 | g.append('path') 868 | .attr('d', axis) 869 | .attr('class', 'asm-axis'); 870 | var seq = Array.apply(0, Array(11)).map(function(x, y) { 871 | return y * 10; 872 | }); 873 | seq.forEach(function(d, index) { 874 | var arc = d3.svg.arc() 875 | .innerRadius(radii.percent.majorTick[0]) 876 | .outerRadius(radii.percent.majorTick[1]) 877 | .startAngle(scale(d)) 878 | .endAngle(scale(d)); 879 | g.append('path') 880 | .attr('d', arc) 881 | .attr('class', 'asm-majorTick'); 882 | 883 | }); 884 | var seq = Array.apply(0, Array(50)).map(function(x, y) { 885 | return y * 2; 886 | }); 887 | seq.forEach(function(d) { 888 | var arc = d3.svg.arc() 889 | .innerRadius(radii.percent.minorTick[0]) 890 | .outerRadius(radii.percent.minorTick[1]) 891 | .startAngle(scale(d)) 892 | .endAngle(scale(d)); 893 | g.append('path') 894 | .attr('d', arc) 895 | .attr('class', 'asm-minorTick'); 896 | }); 897 | } 898 | 899 | 900 | function cegma_axis(parent, radii, scale) { 901 | var g = parent.append('g'); 902 | var axis = d3.svg.arc() 903 | .innerRadius(radii.ceg[2]) 904 | .outerRadius(radii.ceg[2]) 905 | .startAngle(scale(0)) 906 | .endAngle(scale(100)); 907 | g.append('path') 908 | .attr('d', axis) 909 | .attr('class', 'asm-axis'); 910 | var seq = Array.apply(0, Array(10)).map(function(x, y) { 911 | return y * 10; 912 | }); 913 | seq.forEach(function(d, index) { 914 | var arc = d3.svg.arc() 915 | .innerRadius(radii.ceg.majorTick[0]) 916 | .outerRadius(radii.ceg.majorTick[1]) 917 | .startAngle(scale(d)) 918 | .endAngle(scale(d)); 919 | g.append('path') 920 | .attr('d', arc) 921 | .attr('class', 'asm-majorTick'); 922 | if (d % 20 == 0) { 923 | var x = Math.cos(scale(d) - Math.PI / 2) * (radii.ceg.majorTick[1] + 5); 924 | var y = Math.sin(scale(d) - Math.PI / 2) * (radii.ceg.majorTick[1] + 5); 925 | g.append('text') 926 | .text(function() { 927 | return d > 0 ? d : d + '%' 928 | }) 929 | .attr('transform', 'translate(' + x + ',' + y + ') rotate(' + scale(d) / (Math.PI / 180) + ')'); 930 | } 931 | }); 932 | 933 | var seq = Array.apply(0, Array(21)).map(function(x, y) { 934 | return y * 5; 935 | }); 936 | seq.forEach(function(d) { 937 | var arc = d3.svg.arc() 938 | .innerRadius(radii.ceg.minorTick[0]) 939 | .outerRadius(radii.ceg.minorTick[1]) 940 | .startAngle(scale(d)) 941 | .endAngle(scale(d)); 942 | g.append('path') 943 | .attr('d', arc) 944 | .attr('class', 'asm-minorTick'); 945 | }); 946 | 947 | } 948 | 949 | function plot_arc(parent, inner, outer, start, end, css) { 950 | var arc = d3.svg.arc() 951 | .innerRadius(inner) 952 | .outerRadius(outer) 953 | .startAngle(start) 954 | .endAngle(end); 955 | parent.append('path') 956 | .attr('d', arc) 957 | .attr('class', css); 958 | } 959 | 960 | function plot_rect(parent, x1, y1, width, height, css) { 961 | parent.append('rect') 962 | .attr('x', x1) 963 | .attr('y', y1 - height + 20) 964 | .attr('width', width) 965 | .attr('height', height) 966 | .attr('class', css); 967 | } 968 | 969 | function toInt(number) { 970 | number = number.replace(/[,\s]+/g, '') 971 | var suffix = number.slice(-2) 972 | if (suffix.match(/\w[bB]/)) { 973 | number = number.replace(suffix, '') 974 | suffix = suffix.toLowerCase() 975 | var convert = { 976 | 'kb': 1000, 977 | 'mb': 1000000, 978 | 'gb': 1000000000, 979 | 'tb': 1000000000000 980 | }; 981 | if (isNaN(parseFloat(number)) || !isFinite(number)) { 982 | return 0; 983 | } 984 | number = number * convert[suffix]; 985 | } 986 | return number 987 | } 988 | 989 | function getReadableSeqSizeString(seqSizeInBases, fixed) { 990 | // function based on answer at http://stackoverflow.com/questions/10420352/converting-file-size-in-bytes-to-human-readable 991 | var i = -1; 992 | var baseUnits = [' kB', ' MB', ' GB', ' TB']; 993 | do { 994 | seqSizeInBases = seqSizeInBases / 1000; 995 | i++; 996 | } while (seqSizeInBases >= 1000); 997 | fixed = fixed ? fixed : fixed == 0 ? 0 : 1; 998 | return Math.max(seqSizeInBases, 0.1).toFixed(fixed) + baseUnits[i]; 999 | }; 1000 | -------------------------------------------------------------------------------- /js/d3-tip.js: -------------------------------------------------------------------------------- 1 | // d3.tip 2 | // Copyright (c) 2013 Justin Palmer 3 | // 4 | // Tooltips for d3.js SVG visualizations 5 | 6 | // Public - contructs a new tooltip 7 | // 8 | // Returns a tip 9 | d3.tip = function() { 10 | var direction = d3_tip_direction, 11 | offset = d3_tip_offset, 12 | html = d3_tip_html, 13 | node = initNode(), 14 | svg = null, 15 | point = null, 16 | target = null 17 | 18 | function tip(vis) { 19 | svg = getSVGNode(vis) 20 | point = svg.createSVGPoint() 21 | document.body.appendChild(node) 22 | } 23 | 24 | // Public - show the tooltip on the screen 25 | // 26 | // Returns a tip 27 | tip.show = function() { 28 | var args = Array.prototype.slice.call(arguments) 29 | if(args[args.length - 1] instanceof SVGElement) target = args.pop() 30 | 31 | var content = html.apply(this, args), 32 | poffset = offset.apply(this, args), 33 | dir = direction.apply(this, args), 34 | nodel = d3.select(node), i = 0, 35 | coords 36 | 37 | nodel.html(content) 38 | .style({ opacity: 1, 'pointer-events': 'all' }) 39 | 40 | while(i--) nodel.classed(directions[i], false) 41 | coords = direction_callbacks.get(dir).apply(this) 42 | nodel.classed(dir, true).style({ 43 | top: (coords.top + poffset[0]) + 'px', 44 | left: (coords.left + poffset[1]) + 'px' 45 | }) 46 | 47 | return tip 48 | } 49 | 50 | // Public - hide the tooltip 51 | // 52 | // Returns a tip 53 | tip.hide = function() { 54 | nodel = d3.select(node) 55 | nodel.style({ opacity: 0, 'pointer-events': 'none' }) 56 | return tip 57 | } 58 | 59 | // Public: Proxy attr calls to the d3 tip container. Sets or gets attribute value. 60 | // 61 | // n - name of the attribute 62 | // v - value of the attribute 63 | // 64 | // Returns tip or attribute value 65 | tip.attr = function(n, v) { 66 | if (arguments.length < 2 && typeof n === 'string') { 67 | return d3.select(node).attr(n) 68 | } else { 69 | var args = Array.prototype.slice.call(arguments) 70 | d3.selection.prototype.attr.apply(d3.select(node), args) 71 | } 72 | 73 | return tip 74 | } 75 | 76 | // Public: Proxy style calls to the d3 tip container. Sets or gets a style value. 77 | // 78 | // n - name of the property 79 | // v - value of the property 80 | // 81 | // Returns tip or style property value 82 | tip.style = function(n, v) { 83 | if (arguments.length < 2 && typeof n === 'string') { 84 | return d3.select(node).style(n) 85 | } else { 86 | var args = Array.prototype.slice.call(arguments) 87 | d3.selection.prototype.style.apply(d3.select(node), args) 88 | } 89 | 90 | return tip 91 | } 92 | 93 | // Public: Set or get the direction of the tooltip 94 | // 95 | // v - One of n(north), s(south), e(east), or w(west), nw(northwest), 96 | // sw(southwest), ne(northeast) or se(southeast) 97 | // 98 | // Returns tip or direction 99 | tip.direction = function(v) { 100 | if (!arguments.length) return direction 101 | direction = v == null ? v : d3.functor(v) 102 | 103 | return tip 104 | } 105 | 106 | // Public: Sets or gets the offset of the tip 107 | // 108 | // v - Array of [x, y] offset 109 | // 110 | // Returns offset or 111 | tip.offset = function(v) { 112 | if (!arguments.length) return offset 113 | offset = v == null ? v : d3.functor(v) 114 | 115 | return tip 116 | } 117 | 118 | // Public: sets or gets the html value of the tooltip 119 | // 120 | // v - String value of the tip 121 | // 122 | // Returns html value or tip 123 | tip.html = function(v) { 124 | if (!arguments.length) return html 125 | html = v == null ? v : d3.functor(v) 126 | 127 | return tip 128 | } 129 | 130 | function d3_tip_direction() { return 'n' } 131 | function d3_tip_offset() { return [0, 0] } 132 | function d3_tip_html() { return ' ' } 133 | 134 | var direction_callbacks = d3.map({ 135 | n: direction_n, 136 | s: direction_s, 137 | e: direction_e, 138 | w: direction_w, 139 | nw: direction_nw, 140 | ne: direction_ne, 141 | sw: direction_sw, 142 | se: direction_se 143 | }), 144 | 145 | directions = direction_callbacks.keys() 146 | 147 | function direction_n() { 148 | var bbox = getScreenBBox() 149 | return { 150 | top: bbox.n.y - node.offsetHeight, 151 | left: bbox.n.x - node.offsetWidth / 2 152 | } 153 | } 154 | 155 | function direction_s() { 156 | var bbox = getScreenBBox() 157 | return { 158 | top: bbox.s.y, 159 | left: bbox.s.x - node.offsetWidth / 2 160 | } 161 | } 162 | 163 | function direction_e() { 164 | var bbox = getScreenBBox() 165 | return { 166 | top: bbox.e.y - node.offsetHeight / 2, 167 | left: bbox.e.x 168 | } 169 | } 170 | 171 | function direction_w() { 172 | var bbox = getScreenBBox() 173 | return { 174 | top: bbox.w.y - node.offsetHeight / 2, 175 | left: bbox.w.x - node.offsetWidth 176 | } 177 | } 178 | 179 | function direction_nw() { 180 | var bbox = getScreenBBox() 181 | return { 182 | top: bbox.nw.y - node.offsetHeight, 183 | left: bbox.nw.x - node.offsetWidth 184 | } 185 | } 186 | 187 | function direction_ne() { 188 | var bbox = getScreenBBox() 189 | return { 190 | top: bbox.ne.y - node.offsetHeight, 191 | left: bbox.ne.x 192 | } 193 | } 194 | 195 | function direction_sw() { 196 | var bbox = getScreenBBox() 197 | return { 198 | top: bbox.sw.y, 199 | left: bbox.sw.x - node.offsetWidth 200 | } 201 | } 202 | 203 | function direction_se() { 204 | var bbox = getScreenBBox() 205 | return { 206 | top: bbox.se.y, 207 | left: bbox.e.x 208 | } 209 | } 210 | 211 | function initNode() { 212 | var node = d3.select(document.createElement('div')) 213 | node.style({ 214 | position: 'absolute', 215 | opacity: 0, 216 | pointerEvents: 'none', 217 | boxSizing: 'border-box' 218 | }) 219 | 220 | return node.node() 221 | } 222 | 223 | function getSVGNode(el) { 224 | el = el.node() 225 | if(el.tagName.toLowerCase() == 'svg') 226 | return el 227 | 228 | return el.ownerSVGElement 229 | } 230 | 231 | // Private - gets the screen coordinates of a shape 232 | // 233 | // Given a shape on the screen, will return an SVGPoint for the directions 234 | // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest), 235 | // sw(southwest). 236 | // 237 | // +-+-+ 238 | // | | 239 | // + + 240 | // | | 241 | // +-+-+ 242 | // 243 | // Returns an Object {n, s, e, w, nw, sw, ne, se} 244 | function getScreenBBox() { 245 | var targetel = target || d3.event.target, 246 | bbox = {}, 247 | matrix = targetel.getScreenCTM(), 248 | tbbox = targetel.getBBox(), 249 | width = tbbox.width, 250 | height = tbbox.height, 251 | x = tbbox.x, 252 | y = tbbox.y, 253 | scrollTop = document.documentElement.scrollTop || document.body.scrollTop, 254 | scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft 255 | 256 | 257 | point.x = x + scrollLeft 258 | point.y = y + scrollTop 259 | bbox.nw = point.matrixTransform(matrix) 260 | point.x += width 261 | bbox.ne = point.matrixTransform(matrix) 262 | point.y += height 263 | bbox.se = point.matrixTransform(matrix) 264 | point.x -= width 265 | bbox.sw = point.matrixTransform(matrix) 266 | point.y -= height / 2 267 | bbox.w = point.matrixTransform(matrix) 268 | point.x += width 269 | bbox.e = point.matrixTransform(matrix) 270 | point.x -= width / 2 271 | point.y -= height / 2 272 | bbox.n = point.matrixTransform(matrix) 273 | point.y += height 274 | bbox.s = point.matrixTransform(matrix) 275 | 276 | return bbox 277 | } 278 | 279 | return tip 280 | }; 281 | -------------------------------------------------------------------------------- /js/jquery.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ 2 | !function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f 3 | }}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML="
a",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/\s*$/g,sb={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:l.htmlSerialize?[0,"",""]:[1,"X
","
"]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?""!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("