aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatarAgustin Henze <tin@sluc.org.ar>2014-06-13 21:51:04 -0300
committerLibravatarAgustin Henze <tin@sluc.org.ar>2014-06-13 21:51:04 -0300
commit3dddbd8cc879402c2047919bccd20e6697082657 (patch)
tree38d6290f37be1d67d91c46027974e6ee3372e232
parent7ac2cf148f7a8ea0de126fed3360b49964ce9b45 (diff)
parent58c4878526dec5510f23c812274686787d8724ba (diff)
downloadnikola-3dddbd8cc879402c2047919bccd20e6697082657.tar.bz2
nikola-3dddbd8cc879402c2047919bccd20e6697082657.tar.xz
nikola-3dddbd8cc879402c2047919bccd20e6697082657.tar.zst
Merge tag 'upstream/7.0.1'
Upstream version 7.0.1
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml17
-rw-r--r--AUTHORS.txt8
-rw-r--r--CHANGES.txt177
-rw-r--r--README.rst28
-rw-r--r--bower.json16
-rw-r--r--bower_components/bootstrap/.bower.json35
-rw-r--r--bower_components/bootstrap/Gruntfile.js421
-rw-r--r--bower_components/bootstrap/LICENSE21
-rw-r--r--bower_components/bootstrap/README.md173
-rw-r--r--bower_components/bootstrap/bower.json24
-rw-r--r--bower_components/bootstrap/dist/css/bootstrap-theme.css347
-rw-r--r--bower_components/bootstrap/dist/css/bootstrap-theme.css.map1
-rw-r--r--bower_components/bootstrap/dist/css/bootstrap.css.map1
-rw-r--r--bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eotbin0 -> 20335 bytes
-rw-r--r--bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg229
-rw-r--r--bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttfbin0 -> 41280 bytes
-rw-r--r--bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woffbin0 -> 23320 bytes
-rw-r--r--bower_components/bootstrap/fonts/glyphicons-halflings-regular.eotbin0 -> 20335 bytes
-rw-r--r--bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg229
-rw-r--r--bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttfbin0 -> 41280 bytes
-rw-r--r--bower_components/bootstrap/fonts/glyphicons-halflings-regular.woffbin0 -> 23320 bytes
-rw-r--r--bower_components/bootstrap/grunt/bs-glyphicons-data-generator.js34
-rw-r--r--bower_components/bootstrap/grunt/bs-lessdoc-parser.js236
-rw-r--r--bower_components/bootstrap/grunt/bs-raw-files-generator.js31
-rw-r--r--bower_components/bootstrap/grunt/shrinkwrap.js28
-rw-r--r--bower_components/bootstrap/js/affix.js137
-rw-r--r--bower_components/bootstrap/js/alert.js88
-rw-r--r--bower_components/bootstrap/js/button.js107
-rw-r--r--bower_components/bootstrap/js/carousel.js205
-rw-r--r--bower_components/bootstrap/js/collapse.js170
-rw-r--r--bower_components/bootstrap/js/dropdown.js147
-rw-r--r--bower_components/bootstrap/js/modal.js243
-rw-r--r--bower_components/bootstrap/js/popover.js110
-rw-r--r--bower_components/bootstrap/js/scrollspy.js153
-rw-r--r--bower_components/bootstrap/js/tab.js125
-rw-r--r--bower_components/bootstrap/js/tooltip.js399
-rw-r--r--bower_components/bootstrap/js/transition.js48
-rw-r--r--bower_components/bootstrap/less/alerts.less67
-rw-r--r--bower_components/bootstrap/less/badges.less55
-rw-r--r--bower_components/bootstrap/less/bootstrap.less49
-rw-r--r--bower_components/bootstrap/less/breadcrumbs.less26
-rw-r--r--bower_components/bootstrap/less/button-groups.less226
-rw-r--r--bower_components/bootstrap/less/buttons.less159
-rw-r--r--bower_components/bootstrap/less/carousel.less232
-rw-r--r--bower_components/bootstrap/less/close.less33
-rw-r--r--bower_components/bootstrap/less/code.less63
-rw-r--r--bower_components/bootstrap/less/component-animations.less29
-rw-r--r--bower_components/bootstrap/less/dropdowns.less213
-rw-r--r--bower_components/bootstrap/less/forms.less438
-rw-r--r--bower_components/bootstrap/less/glyphicons.less233
-rw-r--r--bower_components/bootstrap/less/grid.less84
-rw-r--r--bower_components/bootstrap/less/input-groups.less162
-rw-r--r--bower_components/bootstrap/less/jumbotron.less44
-rw-r--r--bower_components/bootstrap/less/labels.less64
-rw-r--r--bower_components/bootstrap/less/list-group.less110
-rw-r--r--bower_components/bootstrap/less/media.less56
-rw-r--r--bower_components/bootstrap/less/mixins.less929
-rw-r--r--bower_components/bootstrap/less/modals.less139
-rw-r--r--bower_components/bootstrap/less/navbar.less616
-rw-r--r--bower_components/bootstrap/less/navs.less242
-rw-r--r--bower_components/bootstrap/less/normalize.less423
-rw-r--r--bower_components/bootstrap/less/pager.less55
-rw-r--r--bower_components/bootstrap/less/pagination.less88
-rw-r--r--bower_components/bootstrap/less/panels.less241
-rw-r--r--bower_components/bootstrap/less/popovers.less133
-rw-r--r--bower_components/bootstrap/less/print.less101
-rw-r--r--bower_components/bootstrap/less/progress-bars.less80
-rw-r--r--bower_components/bootstrap/less/responsive-utilities.less92
-rw-r--r--bower_components/bootstrap/less/scaffolding.less134
-rw-r--r--bower_components/bootstrap/less/tables.less233
-rw-r--r--bower_components/bootstrap/less/theme.less247
-rw-r--r--bower_components/bootstrap/less/thumbnails.less36
-rw-r--r--bower_components/bootstrap/less/tooltip.less95
-rw-r--r--bower_components/bootstrap/less/type.less293
-rw-r--r--bower_components/bootstrap/less/utilities.less56
-rw-r--r--bower_components/bootstrap/less/variables.less829
-rw-r--r--bower_components/bootstrap/less/wells.less29
-rw-r--r--bower_components/bootstrap/package.json70
-rw-r--r--bower_components/bootstrap/test-infra/README.md100
-rw-r--r--bower_components/bootstrap/test-infra/npm-shrinkwrap.canonical.json1
-rw-r--r--bower_components/bootstrap/test-infra/requirements.txt1
-rwxr-xr-xbower_components/bootstrap/test-infra/s3_cache.py107
-rw-r--r--bower_components/bootstrap/test-infra/sauce_browsers.yml83
-rwxr-xr-xbower_components/bootstrap/test-infra/uncached-npm-install.sh4
-rw-r--r--bower_components/jquery-colorbox/.bower.json50
-rw-r--r--bower_components/jquery-colorbox/README.md576
-rw-r--r--bower_components/jquery-colorbox/bower.json41
-rw-r--r--bower_components/jquery-colorbox/example1/colorbox.css70
-rw-r--r--bower_components/jquery-colorbox/example1/images/border.png (renamed from nikola/data/themes/bootstrap/assets/css/images/border.png)bin112 -> 112 bytes
-rw-r--r--bower_components/jquery-colorbox/example1/images/controls.pngbin0 -> 2893 bytes
-rw-r--r--bower_components/jquery-colorbox/example1/images/loading.gifbin0 -> 9427 bytes
-rw-r--r--bower_components/jquery-colorbox/example1/images/loading_background.png (renamed from nikola/data/themes/bootstrap/assets/css/images/loading_background.png)bin157 -> 157 bytes
-rw-r--r--bower_components/jquery-colorbox/example1/images/overlay.png (renamed from nikola/data/themes/bootstrap/assets/css/images/overlay.png)bin182 -> 182 bytes
-rw-r--r--bower_components/jquery-colorbox/example2/colorbox.css50
-rw-r--r--bower_components/jquery-colorbox/example2/images/controls.pngbin0 -> 570 bytes
-rw-r--r--bower_components/jquery-colorbox/example2/images/loading.gifbin0 -> 9427 bytes
-rw-r--r--bower_components/jquery-colorbox/example3/colorbox.css45
-rw-r--r--bower_components/jquery-colorbox/example3/images/controls.pngbin0 -> 1633 bytes
-rw-r--r--bower_components/jquery-colorbox/example3/images/loading.gifbin0 -> 9427 bytes
-rw-r--r--bower_components/jquery-colorbox/example4/colorbox.css66
-rw-r--r--bower_components/jquery-colorbox/example4/images/border1.pngbin0 -> 1057 bytes
-rw-r--r--bower_components/jquery-colorbox/example4/images/border2.pngbin0 -> 170 bytes
-rw-r--r--bower_components/jquery-colorbox/example4/images/loading.gifbin0 -> 9427 bytes
-rw-r--r--bower_components/jquery-colorbox/example5/colorbox.css58
-rw-r--r--bower_components/jquery-colorbox/example5/images/border.pngbin0 -> 163 bytes
-rw-r--r--bower_components/jquery-colorbox/example5/images/controls.pngbin0 -> 2033 bytes
-rw-r--r--bower_components/jquery-colorbox/example5/images/loading.gifbin0 -> 9427 bytes
-rw-r--r--bower_components/jquery-colorbox/example5/images/loading_background.pngbin0 -> 166 bytes
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-ar.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-bg.js16
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-ca.js13
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-cs.js16
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-da.js16
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-de.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-es.js13
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-et.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-fa.js18
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-fi.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-fr.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-gl.js13
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-gr.js16
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-he.js16
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-hr.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-hu.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-id.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-it.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-ja.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-kr.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-lt.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-lv.js16
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-my.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-nl.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-no.js16
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-pl.js16
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-pt-br.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-ro.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-ru.js16
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-si.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-sk.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-sr.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-sv.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-tr.js19
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-uk.js16
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-CN.js15
-rw-r--r--bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-TW.js15
-rw-r--r--bower_components/jquery-colorbox/jquery.colorbox.js1090
-rw-r--r--bower_components/jquery/.bower.json37
-rw-r--r--bower_components/jquery/MIT-LICENSE.txt (renamed from nikola/plugins/task/localsearch/MIT-LICENSE.txt)3
-rw-r--r--bower_components/jquery/bower.json27
-rw-r--r--bower_components/jquery/dist/jquery.js10308
-rw-r--r--bower_components/jquery/src/ajax.js807
-rw-r--r--bower_components/jquery/src/ajax/jsonp.js89
-rw-r--r--bower_components/jquery/src/ajax/load.js75
-rw-r--r--bower_components/jquery/src/ajax/parseJSON.js51
-rw-r--r--bower_components/jquery/src/ajax/parseXML.js31
-rw-r--r--bower_components/jquery/src/ajax/script.js93
-rw-r--r--bower_components/jquery/src/ajax/var/nonce.js5
-rw-r--r--bower_components/jquery/src/ajax/var/rquery.js3
-rw-r--r--bower_components/jquery/src/ajax/xhr.js196
-rw-r--r--bower_components/jquery/src/attributes.js11
-rw-r--r--bower_components/jquery/src/attributes/attr.js271
-rw-r--r--bower_components/jquery/src/attributes/classes.js157
-rw-r--r--bower_components/jquery/src/attributes/prop.js134
-rw-r--r--bower_components/jquery/src/attributes/support.js62
-rw-r--r--bower_components/jquery/src/attributes/val.js178
-rw-r--r--bower_components/jquery/src/callbacks.js205
-rw-r--r--bower_components/jquery/src/core.js534
-rw-r--r--bower_components/jquery/src/core/access.js60
-rw-r--r--bower_components/jquery/src/core/init.js132
-rw-r--r--bower_components/jquery/src/core/parseHTML.js39
-rw-r--r--bower_components/jquery/src/core/ready.js152
-rw-r--r--bower_components/jquery/src/core/var/rsingleTag.js4
-rw-r--r--bower_components/jquery/src/css.js504
-rw-r--r--bower_components/jquery/src/css/addGetHookIf.js32
-rw-r--r--bower_components/jquery/src/css/curCSS.js117
-rw-r--r--bower_components/jquery/src/css/defaultDisplay.js69
-rw-r--r--bower_components/jquery/src/css/hiddenVisibleSelectors.js20
-rw-r--r--bower_components/jquery/src/css/support.js149
-rw-r--r--bower_components/jquery/src/css/swap.js28
-rw-r--r--bower_components/jquery/src/css/var/cssExpand.js3
-rw-r--r--bower_components/jquery/src/css/var/isHidden.js13
-rw-r--r--bower_components/jquery/src/css/var/rmargin.js3
-rw-r--r--bower_components/jquery/src/css/var/rnumnonpx.js5
-rw-r--r--bower_components/jquery/src/data.js335
-rw-r--r--bower_components/jquery/src/data/accepts.js21
-rw-r--r--bower_components/jquery/src/data/support.js25
-rw-r--r--bower_components/jquery/src/deferred.js150
-rw-r--r--bower_components/jquery/src/deprecated.js13
-rw-r--r--bower_components/jquery/src/dimensions.js50
-rw-r--r--bower_components/jquery/src/effects.js656
-rw-r--r--bower_components/jquery/src/effects/Tween.js114
-rw-r--r--bower_components/jquery/src/effects/animatedSelector.js13
-rw-r--r--bower_components/jquery/src/effects/support.js55
-rw-r--r--bower_components/jquery/src/event.js1037
-rw-r--r--bower_components/jquery/src/event/alias.js39
-rw-r--r--bower_components/jquery/src/event/support.js26
-rw-r--r--bower_components/jquery/src/exports/amd.js24
-rw-r--r--bower_components/jquery/src/exports/global.js32
-rw-r--r--bower_components/jquery/src/intro.js44
-rw-r--r--bower_components/jquery/src/jquery.js37
-rw-r--r--bower_components/jquery/src/manipulation.js744
-rw-r--r--bower_components/jquery/src/manipulation/_evalUrl.js18
-rw-r--r--bower_components/jquery/src/manipulation/support.js76
-rw-r--r--bower_components/jquery/src/manipulation/var/rcheckableType.js3
-rw-r--r--bower_components/jquery/src/offset.js211
-rw-r--r--bower_components/jquery/src/outro.js1
-rw-r--r--bower_components/jquery/src/queue.js142
-rw-r--r--bower_components/jquery/src/queue/delay.js22
-rw-r--r--bower_components/jquery/src/selector-sizzle.js14
-rw-r--r--bower_components/jquery/src/selector.js1
-rw-r--r--bower_components/jquery/src/serialize.js110
-rw-r--r--bower_components/jquery/src/sizzle/dist/sizzle.js2044
-rw-r--r--bower_components/jquery/src/support.js58
-rw-r--r--bower_components/jquery/src/traversing.js200
-rw-r--r--bower_components/jquery/src/traversing/findFilter.js100
-rw-r--r--bower_components/jquery/src/traversing/var/rneedsContext.js6
-rw-r--r--bower_components/jquery/src/var/class2type.js4
-rw-r--r--bower_components/jquery/src/var/concat.js5
-rw-r--r--bower_components/jquery/src/var/deletedIds.js3
-rw-r--r--bower_components/jquery/src/var/hasOwn.js5
-rw-r--r--bower_components/jquery/src/var/indexOf.js5
-rw-r--r--bower_components/jquery/src/var/pnum.js3
-rw-r--r--bower_components/jquery/src/var/push.js5
-rw-r--r--bower_components/jquery/src/var/rnotwhite.js3
-rw-r--r--bower_components/jquery/src/var/slice.js5
-rw-r--r--bower_components/jquery/src/var/strundefined.js3
-rw-r--r--bower_components/jquery/src/var/support.js4
-rw-r--r--bower_components/jquery/src/var/toString.js5
-rw-r--r--bower_components/jquery/src/wrap.js75
-rw-r--r--docs/creating-a-theme.txt8
-rw-r--r--docs/extending.txt68
-rw-r--r--docs/getting-help.txt2
-rw-r--r--docs/internals.txt2
-rw-r--r--docs/man/nikola.123
-rw-r--r--docs/manual.txt335
-rw-r--r--docs/social_buttons.txt13
-rw-r--r--docs/sphinx/conf.py94
-rw-r--r--docs/theming.txt4
-rw-r--r--docs/upgrading-to-v6.txt4
-rw-r--r--dodo.py26
-rw-r--r--logo/favicon.pngbin0 -> 7004 bytes
-rw-r--r--logo/favicon.svg83
-rw-r--r--logo/nikola-50px-transparent.pngbin0 -> 2031 bytes
-rw-r--r--logo/nikola.pngbin0 -> 15268 bytes
-rw-r--r--logo/nikola.svg19
-rw-r--r--nikola/__init__.py2
-rw-r--r--nikola/__main__.py123
-rw-r--r--nikola/conf.py.in400
-rw-r--r--nikola/data/samplesite/galleries/demo/tesla2_lg.jpgbin20846 -> 21032 bytes
-rw-r--r--nikola/data/samplesite/galleries/demo/tesla4_lg.jpgbin29282 -> 29468 bytes
-rw-r--r--nikola/data/samplesite/galleries/demo/tesla_conducts_lg.jpgbin18755 -> 18941 bytes
-rw-r--r--nikola/data/samplesite/galleries/demo/tesla_lightning1_lg.jpgbin40194 -> 40380 bytes
-rw-r--r--nikola/data/samplesite/galleries/demo/tesla_lightning2_lg.jpgbin36091 -> 36277 bytes
-rw-r--r--nikola/data/samplesite/galleries/demo/tesla_tower1_lg.jpgbin17188 -> 17374 bytes
-rw-r--r--nikola/data/samplesite/posts/1.rst3
-rw-r--r--nikola/data/samplesite/stories/1.rst2
-rw-r--r--nikola/data/samplesite/stories/a-study-in-scarlet.txt2
-rw-r--r--nikola/data/samplesite/stories/bootstrap-demo.rst2
-rw-r--r--nikola/data/samplesite/stories/charts.txt2
-rw-r--r--nikola/data/samplesite/stories/listings-demo.rst2
-rw-r--r--nikola/data/samplesite/stories/quickref.rst2
-rw-r--r--nikola/data/samplesite/stories/quickstart.rst2
-rw-r--r--nikola/data/samplesite/stories/slides-demo.rst2
-rw-r--r--nikola/data/symlinked.txt151
-rw-r--r--nikola/data/themes/base-jinja/AUTHORS.txt1
-rw-r--r--nikola/data/themes/base-jinja/README.md4
-rw-r--r--nikola/data/themes/base-jinja/bundles2
-rw-r--r--nikola/data/themes/base-jinja/engine1
-rw-r--r--nikola/data/themes/base-jinja/parent1
-rw-r--r--nikola/data/themes/base-jinja/templates/annotation_helper.tmpl16
-rw-r--r--nikola/data/themes/base-jinja/templates/base.tmpl25
-rw-r--r--nikola/data/themes/base-jinja/templates/base_footer.tmpl11
-rw-r--r--nikola/data/themes/base-jinja/templates/base_header.tmpl66
-rw-r--r--nikola/data/themes/base-jinja/templates/base_helper.tmpl103
-rw-r--r--nikola/data/themes/base-jinja/templates/comments_helper.tmpl63
-rw-r--r--nikola/data/themes/base-jinja/templates/comments_helper_disqus.tmpl44
-rw-r--r--nikola/data/themes/base-jinja/templates/comments_helper_facebook.tmpl62
-rw-r--r--nikola/data/themes/base-jinja/templates/comments_helper_googleplus.tmpl17
-rw-r--r--nikola/data/themes/base-jinja/templates/comments_helper_intensedebate.tmpl25
-rw-r--r--nikola/data/themes/base-jinja/templates/comments_helper_isso.tmpl20
-rw-r--r--nikola/data/themes/base-jinja/templates/comments_helper_livefyre.tmpl33
-rw-r--r--nikola/data/themes/base-jinja/templates/comments_helper_mustache.tmpl5
-rw-r--r--nikola/data/themes/base-jinja/templates/comments_helper_muut.tmpl13
-rw-r--r--nikola/data/themes/base-jinja/templates/crumbs.tmpl13
-rw-r--r--nikola/data/themes/base-jinja/templates/gallery.tmpl36
-rw-r--r--nikola/data/themes/base-jinja/templates/index.tmpl34
-rw-r--r--nikola/data/themes/base-jinja/templates/index_helper.tmpl27
-rw-r--r--nikola/data/themes/base-jinja/templates/list.tmpl19
-rw-r--r--nikola/data/themes/base-jinja/templates/list_post.tmpl19
-rw-r--r--nikola/data/themes/base-jinja/templates/listing.tmpl23
-rw-r--r--nikola/data/themes/base-jinja/templates/post.tmpl39
-rw-r--r--nikola/data/themes/base-jinja/templates/post_header.tmpl49
-rw-r--r--nikola/data/themes/base-jinja/templates/post_helper.tmpl76
-rw-r--r--nikola/data/themes/base-jinja/templates/post_list_directive.tmpl18
-rw-r--r--nikola/data/themes/base-jinja/templates/slides.tmpl24
-rw-r--r--nikola/data/themes/base-jinja/templates/story.tmpl37
-rw-r--r--nikola/data/themes/base-jinja/templates/tag.tmpl40
-rw-r--r--nikola/data/themes/base-jinja/templates/tagindex.tmpl2
-rw-r--r--nikola/data/themes/base-jinja/templates/tags.tmpl30
-rw-r--r--nikola/data/themes/base/README.md2
-rw-r--r--nikola/data/themes/base/assets/css/theme.css256
-rw-r--r--nikola/data/themes/base/assets/js/html5.js8
-rw-r--r--nikola/data/themes/base/assets/js/mathjax.js1
-rw-r--r--nikola/data/themes/base/bundles4
-rw-r--r--nikola/data/themes/base/messages/messages_bg.py8
-rw-r--r--nikola/data/themes/base/messages/messages_ca.py8
-rw-r--r--nikola/data/themes/base/messages/messages_cs.py8
-rw-r--r--nikola/data/themes/base/messages/messages_de.py10
-rw-r--r--nikola/data/themes/base/messages/messages_el.py8
-rw-r--r--nikola/data/themes/base/messages/messages_en.py8
-rw-r--r--nikola/data/themes/base/messages/messages_eo.py8
-rw-r--r--nikola/data/themes/base/messages/messages_es.py12
-rw-r--r--nikola/data/themes/base/messages/messages_et.py8
-rw-r--r--nikola/data/themes/base/messages/messages_eu.py8
-rw-r--r--nikola/data/themes/base/messages/messages_fa.py14
-rw-r--r--nikola/data/themes/base/messages/messages_fi.py14
-rw-r--r--nikola/data/themes/base/messages/messages_fr.py12
-rw-r--r--nikola/data/themes/base/messages/messages_hi.py8
-rw-r--r--nikola/data/themes/base/messages/messages_hr.py12
-rw-r--r--nikola/data/themes/base/messages/messages_it.py14
-rw-r--r--nikola/data/themes/base/messages/messages_ja.py14
-rw-r--r--nikola/data/themes/base/messages/messages_nb.py8
-rw-r--r--nikola/data/themes/base/messages/messages_nl.py12
-rw-r--r--nikola/data/themes/base/messages/messages_pl.py8
-rw-r--r--nikola/data/themes/base/messages/messages_pt_br.py12
-rw-r--r--nikola/data/themes/base/messages/messages_ru.py12
-rw-r--r--nikola/data/themes/base/messages/messages_sk.py33
-rw-r--r--nikola/data/themes/base/messages/messages_sl.py12
l---------nikola/data/themes/base/messages/messages_sl_si.py1
-rw-r--r--[l---------]nikola/data/themes/base/messages/messages_tr.py34
-rw-r--r--nikola/data/themes/base/messages/messages_tr_tr.py31
-rw-r--r--nikola/data/themes/base/messages/messages_ur.py12
-rw-r--r--nikola/data/themes/base/messages/messages_zh_cn.py8
-rw-r--r--nikola/data/themes/base/templates/base.tmpl52
-rw-r--r--nikola/data/themes/base/templates/base_footer.tmpl11
-rw-r--r--nikola/data/themes/base/templates/base_header.tmpl66
-rw-r--r--nikola/data/themes/base/templates/base_helper.tmpl120
-rw-r--r--nikola/data/themes/base/templates/comments_helper.tmpl26
-rw-r--r--nikola/data/themes/base/templates/comments_helper_disqus.tmpl (renamed from nikola/data/themes/base/templates/disqus_helper.tmpl)20
-rw-r--r--nikola/data/themes/base/templates/comments_helper_facebook.tmpl (renamed from nikola/data/themes/base/templates/facebook_helper.tmpl)0
-rw-r--r--nikola/data/themes/base/templates/comments_helper_googleplus.tmpl (renamed from nikola/data/themes/base/templates/googleplus_helper.tmpl)0
-rw-r--r--nikola/data/themes/base/templates/comments_helper_intensedebate.tmpl (renamed from nikola/data/themes/base/templates/intensedebate_helper.tmpl)4
-rw-r--r--nikola/data/themes/base/templates/comments_helper_isso.tmpl (renamed from nikola/data/themes/base/templates/isso_helper.tmpl)0
-rw-r--r--nikola/data/themes/base/templates/comments_helper_livefyre.tmpl (renamed from nikola/data/themes/base/templates/livefyre_helper.tmpl)12
-rw-r--r--nikola/data/themes/base/templates/comments_helper_mustache.tmpl (renamed from nikola/data/themes/base/templates/mustache-comment-form.tmpl)0
-rw-r--r--nikola/data/themes/base/templates/comments_helper_muut.tmpl (renamed from nikola/data/themes/base/templates/moot_helper.tmpl)4
-rw-r--r--nikola/data/themes/base/templates/crumbs.tmpl2
-rw-r--r--nikola/data/themes/base/templates/gallery.tmpl6
-rw-r--r--nikola/data/themes/base/templates/index.tmpl49
-rw-r--r--nikola/data/themes/base/templates/index_helper.tmpl13
-rw-r--r--nikola/data/themes/base/templates/list.tmpl25
-rw-r--r--nikola/data/themes/base/templates/list_post.tmpl25
-rw-r--r--nikola/data/themes/base/templates/listing.tmpl6
-rw-r--r--nikola/data/themes/base/templates/post.tmpl53
-rw-r--r--nikola/data/themes/base/templates/post_header.tmpl49
-rw-r--r--nikola/data/themes/base/templates/post_helper.tmpl63
-rw-r--r--nikola/data/themes/base/templates/post_list_directive.tmpl2
-rw-r--r--nikola/data/themes/base/templates/slides.tmpl6
-rw-r--r--nikola/data/themes/base/templates/story.tmpl37
-rw-r--r--nikola/data/themes/base/templates/tag.tmpl46
-rw-r--r--nikola/data/themes/base/templates/tags.tmpl13
-rw-r--r--nikola/data/themes/bootstrap-jinja/AUTHORS.txt1
-rw-r--r--nikola/data/themes/bootstrap-jinja/README.md23
l---------nikola/data/themes/bootstrap-jinja/assets/css/colorbox.css1
l---------nikola/data/themes/bootstrap-jinja/assets/css/images/controls.png1
l---------nikola/data/themes/bootstrap-jinja/assets/css/images/loading.gif1
l---------nikola/data/themes/bootstrap-jinja/assets/css/theme.css1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ar.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-bg.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ca.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-cs.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-da.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-de.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-es.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-et.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fa.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fi.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fr.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-gl.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-gr.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-he.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-hr.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-hu.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-id.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-it.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ja.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-kr.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-lt.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-lv.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-my.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-nl.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-no.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-pl.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-pt-br.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ro.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ru.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-si.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sk.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sr.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sv.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-tr.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-uk.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-zh-CN.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-zh-TW.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/flowr.plugin.js1
l---------nikola/data/themes/bootstrap-jinja/assets/js/jquery.colorbox.js1
l---------nikola/data/themes/bootstrap-jinja/bundles1
-rw-r--r--nikola/data/themes/bootstrap-jinja/engine1
-rw-r--r--nikola/data/themes/bootstrap-jinja/parent1
-rw-r--r--nikola/data/themes/bootstrap-jinja/templates/base.tmpl86
-rw-r--r--nikola/data/themes/bootstrap-jinja/templates/base_helper.tmpl161
-rw-r--r--nikola/data/themes/bootstrap-jinja/templates/bootstrap_helper.tmpl78
-rw-r--r--nikola/data/themes/bootstrap-jinja/templates/gallery.tmpl93
-rw-r--r--nikola/data/themes/bootstrap-jinja/templates/listing.tmpl28
-rw-r--r--nikola/data/themes/bootstrap-jinja/templates/post.tmpl47
-rw-r--r--nikola/data/themes/bootstrap-jinja/templates/post_header.tmpl40
-rw-r--r--nikola/data/themes/bootstrap-jinja/templates/slides.tmpl24
-rw-r--r--nikola/data/themes/bootstrap-jinja/templates/tags.tmpl26
l---------[-rw-r--r--]nikola/data/themes/bootstrap/assets/css/colorbox.css70
l---------[-rw-r--r--]nikola/data/themes/bootstrap/assets/css/images/controls.pngbin2893 -> 82 bytes
l---------[-rw-r--r--]nikola/data/themes/bootstrap/assets/css/images/loading.gifbin9427 -> 81 bytes
-rw-r--r--nikola/data/themes/bootstrap/assets/css/theme.css71
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ar.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-bg.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ca.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-cs.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-da.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-de.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-es.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-et.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fa.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fi.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fr.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-gl.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-gr.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-he.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-hr.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-hu.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-id.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-it.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ja.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-kr.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-lt.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-lv.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-my.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-nl.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-no.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-pl.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-pt-br.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ro.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ru.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-si.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sk.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sr.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sv.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-tr.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-uk.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-zh-CN.js1
l---------nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-zh-TW.js1
l---------nikola/data/themes/bootstrap/assets/js/jquery.colorbox.js1
-rw-r--r--nikola/data/themes/bootstrap/bundles2
-rw-r--r--nikola/data/themes/bootstrap/templates/base.tmpl56
-rw-r--r--nikola/data/themes/bootstrap/templates/base_helper.tmpl (renamed from nikola/data/themes/bootstrap/templates/bootstrap_helper.tmpl)156
-rw-r--r--nikola/data/themes/bootstrap/templates/gallery.tmpl35
-rw-r--r--nikola/data/themes/bootstrap/templates/listing.tmpl28
-rw-r--r--nikola/data/themes/bootstrap/templates/post.tmpl47
-rw-r--r--nikola/data/themes/bootstrap/templates/slides.tmpl6
-rw-r--r--nikola/data/themes/bootstrap/templates/tags.tmpl26
-rw-r--r--nikola/filters.py78
-rw-r--r--nikola/nikola.py711
-rw-r--r--nikola/packages/README.md5
-rw-r--r--nikola/packages/__init__.py0
-rw-r--r--nikola/packages/tzlocal/LICENSE.txt121
-rw-r--r--nikola/packages/tzlocal/__init__.py7
-rw-r--r--nikola/packages/tzlocal/darwin.py33
-rw-r--r--nikola/packages/tzlocal/unix.py126
-rw-r--r--nikola/packages/tzlocal/win32.py92
-rw-r--r--nikola/packages/tzlocal/windows_tz.py543
-rw-r--r--nikola/plugin_categories.py78
-rw-r--r--nikola/plugins/basic_import.py5
-rw-r--r--nikola/plugins/command/auto.py4
-rw-r--r--nikola/plugins/command/bootswatch_theme.py5
-rw-r--r--nikola/plugins/command/check.py12
-rw-r--r--nikola/plugins/command/console.py116
-rw-r--r--nikola/plugins/command/deploy.py10
-rw-r--r--nikola/plugins/command/github_deploy.plugin9
-rw-r--r--nikola/plugins/command/github_deploy.py271
-rw-r--r--nikola/plugins/command/import_blogger.plugin10
-rw-r--r--nikola/plugins/command/import_blogger.py228
-rw-r--r--nikola/plugins/command/import_feed.plugin10
-rw-r--r--nikola/plugins/command/import_feed.py200
-rw-r--r--nikola/plugins/command/import_wordpress.py10
-rw-r--r--nikola/plugins/command/init.py346
-rw-r--r--nikola/plugins/command/install_plugin.plugin10
-rw-r--r--nikola/plugins/command/install_plugin.py188
-rw-r--r--nikola/plugins/command/install_theme.py4
-rw-r--r--nikola/plugins/command/mincss.py75
-rw-r--r--nikola/plugins/command/new_page.py7
-rw-r--r--nikola/plugins/command/new_post.py105
-rw-r--r--nikola/plugins/command/planetoid.plugin9
-rw-r--r--nikola/plugins/command/planetoid/__init__.py289
-rw-r--r--nikola/plugins/command/plugin.plugin10
-rw-r--r--nikola/plugins/command/plugin.py319
-rw-r--r--nikola/plugins/command/serve.py6
-rw-r--r--nikola/plugins/compile/asciidoc.plugin10
-rw-r--r--nikola/plugins/compile/asciidoc.py71
-rw-r--r--nikola/plugins/compile/bbcode.py80
-rw-r--r--nikola/plugins/compile/html.py24
-rw-r--r--nikola/plugins/compile/ipynb.plugin2
-rw-r--r--nikola/plugins/compile/ipynb/__init__.py26
-rw-r--r--nikola/plugins/compile/markdown/__init__.py49
-rw-r--r--nikola/plugins/compile/markdown/mdx_gist.plugin (renamed from nikola/plugins/compile/bbcode.plugin)7
-rw-r--r--nikola/plugins/compile/markdown/mdx_gist.py18
-rw-r--r--nikola/plugins/compile/markdown/mdx_nikola.plugin (renamed from nikola/plugins/command/mincss.plugin)7
-rw-r--r--nikola/plugins/compile/markdown/mdx_nikola.py24
-rw-r--r--nikola/plugins/compile/markdown/mdx_podcast.plugin9
-rw-r--r--nikola/plugins/compile/markdown/mdx_podcast.py14
-rw-r--r--nikola/plugins/compile/misaka.plugin10
-rw-r--r--nikola/plugins/compile/misaka.py87
-rw-r--r--nikola/plugins/compile/pandoc.py24
-rw-r--r--nikola/plugins/compile/php.py24
-rw-r--r--nikola/plugins/compile/rest/__init__.py26
-rw-r--r--nikola/plugins/compile/rest/chart.py13
-rw-r--r--nikola/plugins/compile/rest/doc.py2
-rw-r--r--nikola/plugins/compile/rest/listing.py1
-rw-r--r--nikola/plugins/compile/rest/post_list.py5
-rw-r--r--nikola/plugins/compile/rest/slides.py9
-rw-r--r--nikola/plugins/compile/rest/vimeo.py6
-rw-r--r--nikola/plugins/compile/rest/youtube.py2
-rw-r--r--nikola/plugins/compile/textile.plugin10
-rw-r--r--nikola/plugins/compile/textile.py76
-rw-r--r--nikola/plugins/compile/txt2tags.plugin10
-rw-r--r--nikola/plugins/compile/txt2tags.py76
-rw-r--r--nikola/plugins/compile/wiki.plugin10
-rw-r--r--nikola/plugins/compile/wiki.py75
-rw-r--r--nikola/plugins/loghandler/stderr.py6
-rw-r--r--nikola/plugins/task/archive.py21
-rw-r--r--nikola/plugins/task/build_less.plugin10
-rw-r--r--nikola/plugins/task/build_less.py118
-rw-r--r--nikola/plugins/task/build_sass.plugin9
-rw-r--r--nikola/plugins/task/build_sass.py139
-rw-r--r--nikola/plugins/task/bundles.py27
-rw-r--r--nikola/plugins/task/copy_assets.py31
-rw-r--r--nikola/plugins/task/galleries.py126
-rw-r--r--nikola/plugins/task/indexes.py62
-rw-r--r--nikola/plugins/task/listings.py67
-rw-r--r--nikola/plugins/task/localsearch.plugin10
-rw-r--r--nikola/plugins/task/localsearch/__init__.py106
-rw-r--r--nikola/plugins/task/localsearch/files/assets/css/img/loader.gifbin4178 -> 0 bytes
-rw-r--r--nikola/plugins/task/localsearch/files/assets/css/img/search.pngbin315 -> 0 bytes
-rw-r--r--nikola/plugins/task/localsearch/files/assets/css/tipuesearch.css159
-rw-r--r--nikola/plugins/task/localsearch/files/assets/js/tipuesearch.js384
-rw-r--r--nikola/plugins/task/localsearch/files/assets/js/tipuesearch_set.js21
-rw-r--r--nikola/plugins/task/localsearch/files/tipue_search.html31
-rw-r--r--nikola/plugins/task/mustache.plugin10
-rw-r--r--nikola/plugins/task/mustache/__init__.py184
-rw-r--r--nikola/plugins/task/mustache/mustache-template.html29
-rw-r--r--nikola/plugins/task/mustache/mustache.html34
-rw-r--r--nikola/plugins/task/pages.py5
-rw-r--r--nikola/plugins/task/posts.py18
-rw-r--r--nikola/plugins/task/redirect.py2
-rw-r--r--nikola/plugins/task/robots.plugin10
-rw-r--r--nikola/plugins/task/robots.py83
-rw-r--r--nikola/plugins/task/rss.py20
-rw-r--r--nikola/plugins/task/sitemap/__init__.py124
-rw-r--r--nikola/plugins/task/tags.py45
-rw-r--r--nikola/plugins/template/jinja.py16
-rw-r--r--nikola/plugins/template/mako.py22
-rw-r--r--nikola/post.py283
-rw-r--r--nikola/utils.py725
-rw-r--r--nikola/winutils.py120
-rw-r--r--requirements-extras.txt (renamed from requirements-full.txt)2
-rw-r--r--requirements-tests.txt5
-rw-r--r--requirements.txt4
-rwxr-xr-xscripts/generate_symlinked_list.sh9
-rwxr-xr-xscripts/getbaseline.sh14
-rwxr-xr-xscripts/getwheelhouse.sh7
-rwxr-xr-xscripts/import_po.py16
-rwxr-xr-xscripts/jinjify.py219
-rwxr-xr-xscripts/nikola37
-rwxr-xr-xscripts/nikola.bat2
-rwxr-xr-xscripts/set_version.py5
-rwxr-xr-xscripts/theme_snapshot2
-rw-r--r--setup.cfg2
-rwxr-xr-xsetup.py134
-rw-r--r--tests/README.rst5
-rw-r--r--tests/__init__.py25
-rw-r--r--tests/base.py79
-rw-r--r--tests/conftest.py8
-rw-r--r--tests/data/translated_titles/conf.py578
-rw-r--r--tests/data/translated_titles/stories/1.pl.txt (renamed from tests/data/translated_titles/stories/1.txt.pl)0
-rw-r--r--tests/test_command_import_wordpress.py1
-rw-r--r--tests/test_command_init.py57
-rw-r--r--tests/test_commands.py18
-rw-r--r--tests/test_compile_markdown.py16
-rw-r--r--tests/test_integration.py82
-rw-r--r--tests/test_rss_feeds.py10
-rw-r--r--tests/test_rst_compiler.py93
-rw-r--r--tests/test_scheduling.py145
-rw-r--r--tests/test_utils.py90
-rw-r--r--translations/nikola.messages/bg.po19
-rw-r--r--translations/nikola.messages/ca.po19
-rw-r--r--translations/nikola.messages/cs.po19
-rw-r--r--translations/nikola.messages/de.po25
-rw-r--r--translations/nikola.messages/el.po19
-rw-r--r--translations/nikola.messages/en.po27
-rw-r--r--translations/nikola.messages/eo.po19
-rw-r--r--translations/nikola.messages/es.po27
-rw-r--r--translations/nikola.messages/et.po19
-rw-r--r--translations/nikola.messages/eu.po19
-rw-r--r--translations/nikola.messages/fa.po24
-rw-r--r--translations/nikola.messages/fi.po27
-rw-r--r--translations/nikola.messages/fr.po22
-rw-r--r--translations/nikola.messages/hi.po19
-rw-r--r--translations/nikola.messages/hr.po23
-rw-r--r--translations/nikola.messages/it.po27
-rw-r--r--translations/nikola.messages/ja.po24
-rw-r--r--translations/nikola.messages/nb.po19
-rw-r--r--translations/nikola.messages/nl.po25
-rw-r--r--translations/nikola.messages/pl.po19
-rw-r--r--translations/nikola.messages/pt_BR.po26
-rw-r--r--translations/nikola.messages/ru.po26
-rw-r--r--translations/nikola.messages/sk.po108
-rw-r--r--translations/nikola.messages/sl.po25
-rw-r--r--translations/nikola.messages/tr.po (renamed from translations/nikola.messages/tr_TR.po)31
-rw-r--r--translations/nikola.messages/ur.po27
-rw-r--r--translations/nikola.messages/zh_CN.po19
628 files changed, 45200 insertions, 5539 deletions
diff --git a/.gitignore b/.gitignore
index ddcf4b3..585ca51 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
*.py[co]
*.db
*~
-dist
+/dist
*.log
*.diff
*.patch
diff --git a/.travis.yml b/.travis.yml
index fc27848..61609aa 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,7 @@ python:
- "2.6"
- "2.7"
- "3.3"
+ - "3.4"
matrix:
include:
- python: "2.7"
@@ -15,17 +16,21 @@ matrix:
env:
NMODE=nikola
install:
- - "if [[ $NMODE == 'nikola' ]]; then wget https://github.com/getnikola/wheelhouse/archive/$(scripts/getpyver.py).zip; fi"
- - "if [[ $NMODE == 'nikola' ]]; then unzip $(scripts/getpyver.py).zip; fi"
- - "if [[ $NMODE == 'nikola' ]]; then pip install --use-wheel --no-index --find-links=wheelhouse-$(scripts/getpyver.py short) lxml Pillow ipython; fi"
- - "if [[ $NMODE == 'nikola' ]]; then pip install -r requirements-tests.txt; fi"
+ - "if [[ $NMODE == 'nikola' ]]; then scripts/getwheelhouse.sh $(scripts/getpyver.py short); fi"
+ - "if [[ $NMODE == 'nikola' ]]; then pip install -r requirements-tests.txt; if [[ \"$?\" == '1' ]]; then cat /home/travis/.pip/pip.log; false; fi; fi"
- "if [[ $NMODE == 'nikola' ]]; then pip install .; fi"
+ - "if [[ $NMODE == 'nikola' ]]; then scripts/getbaseline.sh $(scripts/getpyver.py short); fi"
- "if [[ $NMODE == 'flake8' ]]; then pip install flake8; fi"
# We run tests and nikola (to see if the command is executable) OR flake8.
+# We run `nikola` and `nikola help` because things may break due to human
+# errors in argument parsing (cf. 96e78dd)
+# WARNING: if you edit this, make sure to replicate your changes in dodo.py.
script:
- - "if [[ $NMODE == 'nikola' ]]; then nosetests --with-coverage --cover-package=nikola --with-doctest --doctest-options=+NORMALIZE_WHITESPACE --logging-filter=-yapsy; fi"
+ - "if [[ $NMODE == 'nikola' ]]; then py.test --doctest-modules nikola/; fi"
+ - "if [[ $NMODE == 'nikola' ]]; then py.test --cov nikola --cov-report term-missing tests/; fi"
+ - "if [[ $NMODE == 'nikola' ]]; then nikola; fi"
- "if [[ $NMODE == 'nikola' ]]; then nikola help; fi"
- - "if [[ $NMODE == 'flake8' ]]; then flake8 .; fi"
+ - "if [[ $NMODE == 'flake8' ]]; then flake8 nikola/; fi"
after_success:
- "if [[ $NMODE == 'nikola' ]]; then coveralls; fi"
notifications:
diff --git a/AUTHORS.txt b/AUTHORS.txt
index cfb0ea0..4531602 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -1,5 +1,5 @@
These are the people who have committed code according to GitHub.
-There is probably someone missing if he send me code directly, and
+There is probably someone missing if he sent me code directly, and
for that I am sorry because I believe in giving credit.
If you are here and prefer to be listed in a different way, just
do a PR :-)
@@ -7,10 +7,12 @@ do a PR :-)
-- Roberto Alsina
+Alberto Berti <https://github.com/azazel75>
Aru Sahni <https://github.com/arusahni>
Bluerise <https://github.com/Bluerise>
Chris “Kwpolska” Warrick <https://github.com/Kwpolska>
Daniel Aleksandersen <https://github.com/Aeyoun>
+Dmitry Verkhoturov <https://github.com/paskal>
DoctorMalboro <https://github.com/DoctorMalboro>
Eduardo Schettino <https://github.com/schettino72>
Evgeni Golov <https://github.com/evgeni>
@@ -29,7 +31,7 @@ agustinhenze <https://github.com/agustinhenze>
areski <https://github.com/areski>
bwhmather <https://github.com/bwhmather>
camboris <https://github.com/camboris>
-claxo <https://github.com/claxo>
+Claudio Canepa <https://github.com/ccanepa>
clee <https://github.com/clee>
damianavila <https://github.com/damianavila>
dastagg <https://github.com/dastagg>
@@ -58,7 +60,6 @@ notfoss <https://github.com/notfoss>
numshub <https://github.com/numshub>
onnodb <https://github.com/onnodb>
pabluk <https://github.com/pabluk>
-paskal <https://github.com/paskal>
punchagan <https://github.com/punchagan>
quijot <https://github.com/quijot>
quodlibetor <https://github.com/quodlibetor>
@@ -67,5 +68,6 @@ rafacarrascosa <https://github.com/rafacarrascosa>
rbistolfi <https://github.com/rbistolfi>
snaewe <https://github.com/snaewe>
tolusonaike <https://github.com/tolusonaike>
+Thomas Burette <https://github.com/tburette>
wimpr1m <https://github.com/wimpr1m>
yarko <https://github.com/yarko>
diff --git a/CHANGES.txt b/CHANGES.txt
index 8454939..1e7a8cf 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,10 +1,185 @@
+New in v7.0.1
+=============
+
+Features
+--------
+
+* added ``-e``, ``--edit`` parameter to ``new_post`` and ``new_page`` to open
+ $EDITOR after creation (Issue #1294)
+* added ``scanned`` signal (after posts are scanned) (via Issue #1291)
+* added missing ``initialized`` event (after tasks are loaded) (Issue #1291)
+
+Bugfixes
+--------
+
+* sanitized dates generated by new_post by forcing an ISO 8601-esque
+ format of YYYY-mm-dd HH:MM:SS (Issues #1284, #1313)
+* made github_deploy compatible with Python 3 (Issue #1311)
+* rebuild stuff on TranslatableSettings’ change (Issue #1297)
+* made bootstrap-jinja and bootstrap3-jinja work again, assets were missing
+ (Issue #1309)
+* ignore non-utf8-encoded .html files in sitemaps (Issue #1308)
+* fixed missing assets in Windows (Issue #1306)
+* locales are ignored if there is no config (via Issue #1304)
+* “fixed” a weird bug which tried to find the __file__ of __builtin__
+* made ``nikola init`` locale-independent (via Issues #1288, #1304)
+* fixed theme/plugin installation under Python 2.6 (Issue #1298)
+* removed ``colorama`` and color support under Windows due to Unicode problems
+ (Issue #1288)
+* made ``files/assets/css/code.css`` work again (Issue #1290)
+
+New in v7.0.0
+=============
+
+Features
+--------
+
+* Added ``UNSLUGIFY_TITLES`` option for making titles fetched via the
+ filename regexp prettier (Issue #1282)
+* New dependencies: ``natsort`` (natural sorting in galleries)
+ and ``dateutil`` (replaces ``pytz``)
+* Nikola.commands are now the user-friendly wrappers from console (Issue #1177)
+* Add a ``github_deploy`` command to deploy to GitHub pages (Issue #1208)
+* Remove tidy filter (it was broken due to tidy being ancient) (Issue #1164)
+* Added ``GENERATE_RSS`` setting to allow disabling RSS in Nikola (Issue #1236)
+* Link listings raw sources if COPY_SOURCES is True (Issue #1214)
+* Much more powerful ``nikola plugin`` command (Issue #1189)
+* More powerful console mode allows access to all nikola commands (Issue #830)
+* New ```ROBOTS_EXCLUSIONS``` option listing resources to exclude from sitemap
+ and include in new generated /robots.txt (Issue #804)
+* Generate sitemapindex containing RSS and sitemap files (Issue #804)
+* Support hooks in templates, for use by plugins (Issue #896)
+* Use readline if available (Issue #1238)
+* Replaced ``READ_MORE_LINK`` with ``INDEX_READ_MORE_LINK`` and
+ ``RSS_READ_MORE_LINK`` (Issue #1222)
+* Added reading_time, remaining_reading_time, paragraph_count,
+ remaining_paragraph_count tags for READ_MORE_LINK (Issue #1220)
+* Add canonical link in listings.
+* Added support for new meta files that are the same format as 1-file metadata,
+ allowing for greater flexibility (Issue #954)
+* Colorbox is now internationalized (Issue #1205)
+* Added LOGO_URL and SHOW_BLOG_TITLE=True settings to facilitate showing off logos (Issue #1122)
+* Create automatic story index pages for subfolders, too (Issue #793)
+* New Slovak translation by Tomáš Prékop
+* Created a MarkdownExtension plugin class (Issue #1175)
+* The base theme produces properly sectioned and semantic HTML5 (Issues #1123, #1137)
+* The base theme comes with a new stylish look by default (Issue #1137)
+* The base theme supports Right-to-Left by using ::dir(rtl) CSS4 rules and
+ <html dir="rtl"> tags where valid (Issue #1146)
+* Bootstrap 2 updated to 2.3.2 (via Issue #1137)
+* Added FORCE_ISO8601 setting that currently makes new_post use ISO 8601 dates (via Issue #1156)
+* Added support for TZ specified in post date (Issue #1118)
+* Make ``nikola init`` ask about the site’s settings (Issue #1080)
+* Use natural sorting for files and folders list in listings and galleries (Issue #1144)
+* Added invariance testing (Issue #672)
+* Plugins can inject templates in the system (Issue #1139)
+* ``nikola import_wordpress`` now has a ``--qtranslate`` option, to parse posts
+ in the qtranslate wordpress plugin format and turn them into multilingual
+ Nikola posts (Issue #1072)
+* ``nikola console`` allows for interpreter choice via -b, -i, -p; moreover,
+ support for bpython is not deprecated anymore (Issue #1126)
+* ``retired`` tag for posts has been replaced with ``private`` (via Issue #686)
+* Changed the default TRANSLATIONS_PATTERN to "{path}.{lang}.{ext}". (Issues
+ #990, #829)
+* Backwards compatibility with v5 is broken. Added backwards-incompatible
+ changes. (Issue #829)
+* Added a ``CONTENT_FOOTER_FORMATS`` config option. It is used to format
+ the ``CONTENT_FOOTER`` variable properly, for compatibility with
+ the Translatable Settings feature. The variable takes a dict, the keys
+ of which are languages, and values are (args, kwargs). (Issue #1112)
+* Certain settings are now translatable. As of now, the settings are:
+ BLOG_AUTHOR, BLOG_TITLE, BLOG_DESCRIPTION, LICENSE, CONTENT_FOOTER,
+ SOCIAL_BUTTONS_CODE, SEARCH_FORM, BODY_END, EXTRA_HEAD_DATA,
+ NAVIGATION_LINKS, READ_MORE_LINK (the up-to-date list is available in
+ SITE.TRANSLATABLE_SETTINGS) (Issues #851, #1057, #1061, #1112)
+* New Post.author() returns meta 'author' or BLOG_AUTHOR (Issue #1117)
+* Ship base-jinja, bootstrap-jinja, bootstrap3-jinja with Nikola (Issue #1104)
+* Invert ``HIDE_SOURCELINK`` and ``HIDE_UNTRANSLATED_POSTS`` into
+ ``SHOW_SOURCELINK`` and ``SHOW_UNTRANSLATED_POSTS`` (Issue #1076)
+* Remove old messages left over for backwards compatibility: (Issues #829, #1105)
+
+ - "More posts about", replaced by "More posts about %s"
+ - "Posted", replaced by "Posted:"
+ - "Also available in", replaced by "Also available in:"
+
+* Remove old "sl_SI", "tr_TR" locale aliases (use "sl" and "tr") (Issue #829, #1105)
+* New option RSS_PLAIN to optionally strip HTML from RSS feeds (Issue #1107)
+* Support content key in compilers' create_post (Issue #1098)
+* Use setuptools’ extras feature. Use ``pip install nikola[extras]`` to
+ install Nikola with extras (``requirements-extras.txt``, formerly
+ ``requirements-full.txt`` -- note the name change!) (Issue #1089)
+
+Bugfixes
+--------
+
+* Markdown now outputs code in a reST-like fashion (Issue #1063)
+* code.css is back to supporting only ``pre.code`` (Issue #1063)
+* Links in monthly archives did not have ``/index.html`` if STRIP_INDEXES
+ was set to False (Issue #1263)
+* Fix lxml adding extra root tags being added by lxml by lxml.html.tostring
+* Not having typogrify installed now produces a valid error (Issue #1262)
+* Pages were not rebuilt when DEMOTE_HEADERS was changed (Issue #1261)
+* Removed SCHEDULE_FORCE_TODAY option (Issue #984)
+* Give better error for unknown subcommands (Issue #1233)
+* Handle conf.py for import plugins more generically (Issue #1235)
+* Remove RSS files from the sitemap (Issue #804)
+* ``nikola deploy`` works with DEPLOY_FUTURE = True (Issue #1249)
+* Removed EXTRA_PLUGINS and ENABLED_EXTRAS options (Issue #1247)
+* ``nikola COMMAND -h/--help`` now outputs command help and not Nikola
+ help (showing the command help is standard behavior) (Issue #1245)
+* Redirect pages should have a body linking to the new location
+* The typogrify filter is now Python 3-compatible (Issue #1244)
+* Fix ``nikola auto`` not watching changes in FILES_FOLDERS (Issue #1241)
+* Vimeo and YouTube embedding in reStructuredText is now protocol-relative
+* Don't crash if a unknown kind of path/link is requested (Issue #1236)
+* Don't run ``clean`` and ``list`` outside sites (Issue #1232)
+* If an invalid language is specified, Nikola now shows a helpful error message
+ instead of a traceback (via Issue #1225)
+* Ensure the locale is set correctly when compiling posts (Issue #1219)
+* Fix site-dependent commands (they tried to run anyways) (Issue #1223)
+* Follow symlinks when walking trees (Issue #1206)
+* bootswatch_theme works again and does not try using server hostname=swatch (Issue #1202)
+* Make markdown extensions not break when markdown is not installed (Issue #1201)
+* hidetitle now works in posts, too (Issue #1188)
+* Refactoring of post translation checking (Issue #1194)
+* Trigger rebuild on gallery changes in auto mode (Issue #1180)
+* Galleries are more usable in non-Bootstrap-based themes (Issue #1137)
+* Removed dependency on pytz because mixing it with dateutil breaks things.
+* Use current system TZ for current_time (Issue #1161)
+* Fix links with full path in RSS for files outside root (Issue #1162)
+* ``nikola new_post`` now always outputs a newline at the end of file (Issue #1169)
+* Gallery code cleanup (Issue #1121)
+* USE_FILENAME_AS_TITLE works again (Issue #1073)
+* Rebuild CSS bundles when files change, and also when files are removed (Issue #1153)
+* Don't call links to SITE_URL bad on check when URL_TYPE is 'absolute' (Issue #1147)
+* Trigger rebuilds if URL_TYPE changes (Issue #1095)
+* Eliminate repeated tags in posts (Issue #1142)
+* custom.css not included in bundles
+* Don’t publish email addresses in RSS, use author name via Dublin Core
+* Rebuild a lot of files when TIMEZONE changes (Issue #1110)
+* The ``init`` command and the importers now always output to the CWD.
+ Previously, if you had a ``conf.py`` file higher in the directory structure,
+ Nikola would put the output of those commands in the directory that contained
+ the file. (Issue #1132)
+* Files with non-ASCII characters in filenames are copied only when needed, and
+ not every build (Issue #1129)
+* Split Twitter Cards and Open Graph, enable the latter by default
+* Load html5shiv.js from remote or local server depending on USE_CDN option
+* Fix dependency issue in listings (Issue #1032)
+* Logging configuration has been fixed. The stderr handler can now
+ only be set to DEBUG or INFO (any higher levels are corrected as INFO), and
+ unwanted (i.e. DEBUG) messages are not shown, as intended. (Issue #1111)
+* Catch keyboard exit while serving so traceback does not show (Issue #1124)
+* Support rescanning posts in the Nikola class (Issue #1100)
+* Use TIMEZONE with ``nikola new_post`` and ``nikola new_page``. (Issue #1088)
+
New in v6.4.0
=============
Features
--------
-* Add `nikola new_page` command (equivalent to `nikola new_post -p`) (Issue #1060)
+* Add ``nikola new_page`` command (equivalent to ``nikola new_post -p``) (Issue #1060)
* Add LESS_OPTIONS and SASS_OPTIONS for specifying additional parameters to LESS/Sass compilers (Issue #1020)
* Warn users about bootswatch_theme being incompatible with bootstrap3-gradients
* Add link://filename/foo/bar.rst syntax to refer to the post generated from foo/bar.rst (Issue #1035)
diff --git a/README.rst b/README.rst
index 7803c46..ac7c61c 100644
--- a/README.rst
+++ b/README.rst
@@ -3,18 +3,20 @@ Nikola, a Static Site and Blog Generator
In goes content, out comes a website, ready to deploy.
-.. image:: https://travis-ci.org/getnikola/nikola.png
- :target: https://travis-ci.org/getnikola/nikola
+.. image:: http://img.shields.io/pypi/v/Nikola.png
+ :target: https://pypi.python.org/pypi/Nikola
-.. image:: https://pypip.in/v/Nikola/badge.png
- :target: https://crate.io/packages/Nikola
+.. .. image:: http://img.shields.io/pypi/d/Nikola.png
+.. :target: https://pypi.python.org/pypi/Nikola
-.. image:: https://pypip.in/d/Nikola/badge.png
- :target: https://crate.io/packages/Nikola
+.. image:: http://img.shields.io/travis/getnikola/nikola.png
+ :target: https://travis-ci.org/getnikola/nikola
-.. image:: https://coveralls.io/repos/getnikola/nikola/badge.png?branch=master
+.. image:: http://img.shields.io/coveralls/getnikola/nikola.png
:target: https://coveralls.io/r/getnikola/nikola?branch=master
+.. image:: http://img.shields.io/badge/license-MIT-green.png
+ :target: https://github.com/getnikola/nikola/blob/master/LICENSE.txt
Why Static Websites?
--------------------
@@ -38,7 +40,7 @@ It has many features, but here are some of the nicer ones:
* Syntax highlighting for almost any programming language or markup
* Multilingual sites, `translated to 18 languages.`__
* Doesn't reinvent wheels, leverages existing tools.
-* Python 2.6, 2.7 and 3.3 compatible.
+* Python 2.6, 2.7, 3.3 and 3.4 compatible.
.. _Nikola Handbook: http://getnikola.com/handbook.html#why-static
__ http://users.getnikola.com/
@@ -53,16 +55,14 @@ Installation Instructions
Assuming you have pip installed::
- git clone git://github.com/getnikola/nikola.git
- cd nikola
- pip install .
+ pip install Nikola
For optional features::
- pip install -r requirements-full.txt
-
+ pip install Nikola[extras]
+
For tests (see tests/README.rst for more details)::
- pip install -r requirements-tests.txt
+ pip install Nikola[extras,tests]
For more information, see http://getnikola.com/
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..d55c21c
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,16 @@
+{
+ "name": "Nikola",
+ "version": "0.0.0",
+ "homepage": "https://github.com/getnikola/nikola",
+ "authors": [
+ "Nikola Team <info@getnikola.com>"
+ ],
+ "description": "Nikola",
+ "license": "MIT",
+ "private": true,
+ "dependencies": {
+ "bootstrap": "~3.1.1",
+ "jquery": "<2.0.0",
+ "jquery-colorbox": "~1.5.9"
+ }
+}
diff --git a/bower_components/bootstrap/.bower.json b/bower_components/bootstrap/.bower.json
new file mode 100644
index 0000000..7222108
--- /dev/null
+++ b/bower_components/bootstrap/.bower.json
@@ -0,0 +1,35 @@
+{
+ "name": "bootstrap",
+ "version": "3.1.1",
+ "main": [
+ "./dist/css/bootstrap.css",
+ "./dist/js/bootstrap.js",
+ "./dist/fonts/glyphicons-halflings-regular.eot",
+ "./dist/fonts/glyphicons-halflings-regular.svg",
+ "./dist/fonts/glyphicons-halflings-regular.ttf",
+ "./dist/fonts/glyphicons-halflings-regular.woff"
+ ],
+ "ignore": [
+ "**/.*",
+ "_config.yml",
+ "CNAME",
+ "composer.json",
+ "CONTRIBUTING.md",
+ "docs",
+ "js/tests"
+ ],
+ "dependencies": {
+ "jquery": ">= 1.9.0"
+ },
+ "homepage": "https://github.com/twbs/bootstrap",
+ "_release": "3.1.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "v3.1.1",
+ "commit": "a365d8689c3f3cee7f1acf86b61270ecca8e106d"
+ },
+ "_source": "git://github.com/twbs/bootstrap.git",
+ "_target": "~3.1.1",
+ "_originalSource": "bootstrap",
+ "_direct": true
+} \ No newline at end of file
diff --git a/bower_components/bootstrap/Gruntfile.js b/bower_components/bootstrap/Gruntfile.js
new file mode 100644
index 0000000..600c1f1
--- /dev/null
+++ b/bower_components/bootstrap/Gruntfile.js
@@ -0,0 +1,421 @@
+/*!
+ * Bootstrap's Gruntfile
+ * http://getbootstrap.com
+ * Copyright 2013-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+module.exports = function (grunt) {
+ 'use strict';
+
+ // Force use of Unix newlines
+ grunt.util.linefeed = '\n';
+
+ RegExp.quote = function (string) {
+ return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
+ };
+
+ var fs = require('fs');
+ var path = require('path');
+ var generateGlyphiconsData = require('./grunt/bs-glyphicons-data-generator.js');
+ var BsLessdocParser = require('./grunt/bs-lessdoc-parser.js');
+ var generateRawFilesJs = require('./grunt/bs-raw-files-generator.js');
+ var updateShrinkwrap = require('./grunt/shrinkwrap.js');
+
+ // Project configuration.
+ grunt.initConfig({
+
+ // Metadata.
+ pkg: grunt.file.readJSON('package.json'),
+ banner: '/*!\n' +
+ ' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
+ ' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
+ ' * Licensed under <%= pkg.license.type %> (<%= pkg.license.url %>)\n' +
+ ' */\n',
+ jqueryCheck: 'if (typeof jQuery === \'undefined\') { throw new Error(\'Bootstrap\\\'s JavaScript requires jQuery\') }\n\n',
+
+ // Task configuration.
+ clean: {
+ dist: ['dist', 'docs/dist']
+ },
+
+ jshint: {
+ options: {
+ jshintrc: 'js/.jshintrc'
+ },
+ grunt: {
+ options: {
+ jshintrc: 'grunt/.jshintrc'
+ },
+ src: ['Gruntfile.js', 'grunt/*.js']
+ },
+ src: {
+ src: 'js/*.js'
+ },
+ test: {
+ src: 'js/tests/unit/*.js'
+ },
+ assets: {
+ src: ['docs/assets/js/application.js', 'docs/assets/js/customizer.js']
+ }
+ },
+
+ jscs: {
+ options: {
+ config: 'js/.jscs.json',
+ },
+ grunt: {
+ src: ['Gruntfile.js', 'grunt/*.js']
+ },
+ src: {
+ src: 'js/*.js'
+ },
+ test: {
+ src: 'js/tests/unit/*.js'
+ },
+ assets: {
+ src: ['docs/assets/js/application.js', 'docs/assets/js/customizer.js']
+ }
+ },
+
+ csslint: {
+ options: {
+ csslintrc: 'less/.csslintrc'
+ },
+ src: [
+ 'dist/css/bootstrap.css',
+ 'dist/css/bootstrap-theme.css',
+ 'docs/assets/css/docs.css',
+ 'docs/examples/**/*.css'
+ ]
+ },
+
+ concat: {
+ options: {
+ banner: '<%= banner %>\n<%= jqueryCheck %>',
+ stripBanners: false
+ },
+ bootstrap: {
+ src: [
+ 'js/transition.js',
+ 'js/alert.js',
+ 'js/button.js',
+ 'js/carousel.js',
+ 'js/collapse.js',
+ 'js/dropdown.js',
+ 'js/modal.js',
+ 'js/tooltip.js',
+ 'js/popover.js',
+ 'js/scrollspy.js',
+ 'js/tab.js',
+ 'js/affix.js'
+ ],
+ dest: 'dist/js/<%= pkg.name %>.js'
+ }
+ },
+
+ uglify: {
+ options: {
+ report: 'min'
+ },
+ bootstrap: {
+ options: {
+ banner: '<%= banner %>'
+ },
+ src: '<%= concat.bootstrap.dest %>',
+ dest: 'dist/js/<%= pkg.name %>.min.js'
+ },
+ customize: {
+ options: {
+ preserveComments: 'some'
+ },
+ src: [
+ 'docs/assets/js/vendor/less.min.js',
+ 'docs/assets/js/vendor/jszip.min.js',
+ 'docs/assets/js/vendor/uglify.min.js',
+ 'docs/assets/js/vendor/blob.js',
+ 'docs/assets/js/vendor/filesaver.js',
+ 'docs/assets/js/raw-files.min.js',
+ 'docs/assets/js/customizer.js'
+ ],
+ dest: 'docs/assets/js/customize.min.js'
+ },
+ docsJs: {
+ options: {
+ preserveComments: 'some'
+ },
+ src: [
+ 'docs/assets/js/vendor/holder.js',
+ 'docs/assets/js/application.js'
+ ],
+ dest: 'docs/assets/js/docs.min.js'
+ }
+ },
+
+ less: {
+ compileCore: {
+ options: {
+ strictMath: true,
+ sourceMap: true,
+ outputSourceFiles: true,
+ sourceMapURL: '<%= pkg.name %>.css.map',
+ sourceMapFilename: 'dist/css/<%= pkg.name %>.css.map'
+ },
+ files: {
+ 'dist/css/<%= pkg.name %>.css': 'less/bootstrap.less'
+ }
+ },
+ compileTheme: {
+ options: {
+ strictMath: true,
+ sourceMap: true,
+ outputSourceFiles: true,
+ sourceMapURL: '<%= pkg.name %>-theme.css.map',
+ sourceMapFilename: 'dist/css/<%= pkg.name %>-theme.css.map'
+ },
+ files: {
+ 'dist/css/<%= pkg.name %>-theme.css': 'less/theme.less'
+ }
+ },
+ minify: {
+ options: {
+ cleancss: true,
+ report: 'min'
+ },
+ files: {
+ 'dist/css/<%= pkg.name %>.min.css': 'dist/css/<%= pkg.name %>.css',
+ 'dist/css/<%= pkg.name %>-theme.min.css': 'dist/css/<%= pkg.name %>-theme.css'
+ }
+ }
+ },
+
+ cssmin: {
+ compress: {
+ options: {
+ keepSpecialComments: '*',
+ noAdvanced: true, // turn advanced optimizations off until the issue is fixed in clean-css
+ report: 'min',
+ selectorsMergeMode: 'ie8'
+ },
+ src: [
+ 'docs/assets/css/docs.css',
+ 'docs/assets/css/pygments-manni.css'
+ ],
+ dest: 'docs/assets/css/docs.min.css'
+ }
+ },
+
+ usebanner: {
+ dist: {
+ options: {
+ position: 'top',
+ banner: '<%= banner %>'
+ },
+ files: {
+ src: [
+ 'dist/css/<%= pkg.name %>.css',
+ 'dist/css/<%= pkg.name %>.min.css',
+ 'dist/css/<%= pkg.name %>-theme.css',
+ 'dist/css/<%= pkg.name %>-theme.min.css'
+ ]
+ }
+ }
+ },
+
+ csscomb: {
+ options: {
+ config: 'less/.csscomb.json'
+ },
+ dist: {
+ files: {
+ 'dist/css/<%= pkg.name %>.css': 'dist/css/<%= pkg.name %>.css',
+ 'dist/css/<%= pkg.name %>-theme.css': 'dist/css/<%= pkg.name %>-theme.css'
+ }
+ },
+ examples: {
+ expand: true,
+ cwd: 'docs/examples/',
+ src: ['**/*.css'],
+ dest: 'docs/examples/'
+ }
+ },
+
+ copy: {
+ fonts: {
+ expand: true,
+ src: 'fonts/*',
+ dest: 'dist/'
+ },
+ docs: {
+ expand: true,
+ cwd: './dist',
+ src: [
+ '{css,js}/*.min.*',
+ 'css/*.map',
+ 'fonts/*'
+ ],
+ dest: 'docs/dist'
+ }
+ },
+
+ qunit: {
+ options: {
+ inject: 'js/tests/unit/phantom.js'
+ },
+ files: 'js/tests/index.html'
+ },
+
+ connect: {
+ server: {
+ options: {
+ port: 3000,
+ base: '.'
+ }
+ }
+ },
+
+ jekyll: {
+ docs: {}
+ },
+
+ jade: {
+ compile: {
+ options: {
+ pretty: true,
+ data: function () {
+ var filePath = path.join(__dirname, 'less/variables.less');
+ var fileContent = fs.readFileSync(filePath, {encoding: 'utf8'});
+ var parser = new BsLessdocParser(fileContent);
+ return {sections: parser.parseFile()};
+ }
+ },
+ files: {
+ 'docs/_includes/customizer-variables.html': 'docs/jade/customizer-variables.jade',
+ 'docs/_includes/nav-customize.html': 'docs/jade/customizer-nav.jade'
+ }
+ }
+ },
+
+ validation: {
+ options: {
+ charset: 'utf-8',
+ doctype: 'HTML5',
+ failHard: true,
+ reset: true,
+ relaxerror: [
+ 'Bad value X-UA-Compatible for attribute http-equiv on element meta.',
+ 'Element img is missing required attribute src.'
+ ]
+ },
+ files: {
+ src: '_gh_pages/**/*.html'
+ }
+ },
+
+ watch: {
+ src: {
+ files: '<%= jshint.src.src %>',
+ tasks: ['jshint:src', 'qunit']
+ },
+ test: {
+ files: '<%= jshint.test.src %>',
+ tasks: ['jshint:test', 'qunit']
+ },
+ less: {
+ files: 'less/*.less',
+ tasks: 'less'
+ }
+ },
+
+ sed: {
+ versionNumber: {
+ pattern: (function () {
+ var old = grunt.option('oldver');
+ return old ? RegExp.quote(old) : old;
+ })(),
+ replacement: grunt.option('newver'),
+ recursive: true
+ }
+ },
+
+ 'saucelabs-qunit': {
+ all: {
+ options: {
+ build: process.env.TRAVIS_JOB_ID,
+ concurrency: 10,
+ urls: ['http://127.0.0.1:3000/js/tests/index.html'],
+ browsers: grunt.file.readYAML('test-infra/sauce_browsers.yml')
+ }
+ }
+ },
+
+ exec: {
+ npmUpdate: {
+ command: 'npm update'
+ },
+ npmShrinkWrap: {
+ command: 'npm shrinkwrap --dev'
+ }
+ }
+ });
+
+
+ // These plugins provide necessary tasks.
+ require('load-grunt-tasks')(grunt, {scope: 'devDependencies'});
+
+ // Docs HTML validation task
+ grunt.registerTask('validate-html', ['jekyll', 'validation']);
+
+ // Test task.
+ var testSubtasks = [];
+ // Skip core tests if running a different subset of the test suite
+ if (!process.env.TWBS_TEST || process.env.TWBS_TEST === 'core') {
+ testSubtasks = testSubtasks.concat(['dist-css', 'csslint', 'jshint', 'jscs', 'qunit', 'build-customizer-html']);
+ }
+ // Skip HTML validation if running a different subset of the test suite
+ if (!process.env.TWBS_TEST || process.env.TWBS_TEST === 'validate-html') {
+ testSubtasks.push('validate-html');
+ }
+ // Only run Sauce Labs tests if there's a Sauce access key
+ if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' &&
+ // Skip Sauce if running a different subset of the test suite
+ (!process.env.TWBS_TEST || process.env.TWBS_TEST === 'sauce-js-unit')) {
+ testSubtasks.push('connect');
+ testSubtasks.push('saucelabs-qunit');
+ }
+ grunt.registerTask('test', testSubtasks);
+
+ // JS distribution task.
+ grunt.registerTask('dist-js', ['concat', 'uglify']);
+
+ // CSS distribution task.
+ grunt.registerTask('dist-css', ['less', 'cssmin', 'csscomb', 'usebanner']);
+
+ // Docs distribution task.
+ grunt.registerTask('dist-docs', 'copy:docs');
+
+ // Full distribution task.
+ grunt.registerTask('dist', ['clean', 'dist-css', 'copy:fonts', 'dist-js', 'dist-docs']);
+
+ // Default task.
+ grunt.registerTask('default', ['test', 'dist', 'build-glyphicons-data', 'build-customizer', 'update-shrinkwrap']);
+
+ // Version numbering task.
+ // grunt change-version-number --oldver=A.B.C --newver=X.Y.Z
+ // This can be overzealous, so its changes should always be manually reviewed!
+ grunt.registerTask('change-version-number', 'sed');
+
+ grunt.registerTask('build-glyphicons-data', generateGlyphiconsData);
+
+ // task for building customizer
+ grunt.registerTask('build-customizer', ['build-customizer-html', 'build-raw-files']);
+ grunt.registerTask('build-customizer-html', 'jade');
+ grunt.registerTask('build-raw-files', 'Add scripts/less files to customizer.', function () {
+ var banner = grunt.template.process('<%= banner %>');
+ generateRawFilesJs(banner);
+ });
+
+ // Task for updating the npm packages used by the Travis build.
+ grunt.registerTask('update-shrinkwrap', ['exec:npmUpdate', 'exec:npmShrinkWrap', '_update-shrinkwrap']);
+ grunt.registerTask('_update-shrinkwrap', function () { updateShrinkwrap.call(this, grunt); });
+};
diff --git a/bower_components/bootstrap/LICENSE b/bower_components/bootstrap/LICENSE
new file mode 100644
index 0000000..8d94aa9
--- /dev/null
+++ b/bower_components/bootstrap/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2011-2014 Twitter, Inc
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/bower_components/bootstrap/README.md b/bower_components/bootstrap/README.md
new file mode 100644
index 0000000..60817b7
--- /dev/null
+++ b/bower_components/bootstrap/README.md
@@ -0,0 +1,173 @@
+# [Bootstrap](http://getbootstrap.com) [![Bower version](https://badge.fury.io/bo/bootstrap.png)](http://badge.fury.io/bo/bootstrap) [![Build Status](https://secure.travis-ci.org/twbs/bootstrap.png)](http://travis-ci.org/twbs/bootstrap) [![devDependency Status](https://david-dm.org/twbs/bootstrap/dev-status.png?theme=shields.io)](https://david-dm.org/twbs/bootstrap#info=devDependencies)
+[![Selenium Test Status](https://saucelabs.com/browser-matrix/bootstrap.svg)](https://saucelabs.com/u/bootstrap)
+
+Bootstrap is a sleek, intuitive, and powerful front-end framework for faster and easier web development, created by [Mark Otto](http://twitter.com/mdo) and [Jacob Thornton](http://twitter.com/fat), and maintained by the [core team](https://github.com/twbs?tab=members) with the massive support and involvement of the community.
+
+To get started, check out <http://getbootstrap.com>!
+
+## Table of contents
+
+ - [Quick start](#quick-start)
+ - [Bugs and feature requests](#bugs-and-feature-requests)
+ - [Documentation](#documentation)
+ - [Compiling CSS and JavaScript](#compiling-css-and-javascript)
+ - [Contributing](#contributing)
+ - [Community](#community)
+ - [Versioning](#versioning)
+ - [Authors](#authors)
+ - [Copyright and license](#copyright-and-license)
+
+## Quick start
+
+Three quick start options are available:
+
+- [Download the latest release](https://github.com/twbs/bootstrap/archive/v3.1.1.zip).
+- Clone the repo: `git clone https://github.com/twbs/bootstrap.git`.
+- Install with [Bower](http://bower.io): `bower install bootstrap`.
+
+Read the [Getting Started page](http://getbootstrap.com/getting-started/) for information on the framework contents, templates and examples, and more.
+
+### What's included
+
+Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. You'll see something like this:
+
+```
+bootstrap/
+├── css/
+│ ├── bootstrap.css
+│ ├── bootstrap.min.css
+│ ├── bootstrap-theme.css
+│ └── bootstrap-theme.min.css
+├── js/
+│ ├── bootstrap.js
+│ └── bootstrap.min.js
+└── fonts/
+ ├── glyphicons-halflings-regular.eot
+ ├── glyphicons-halflings-regular.svg
+ ├── glyphicons-halflings-regular.ttf
+ └── glyphicons-halflings-regular.woff
+```
+
+We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). Fonts from Glyphicons are included, as is the optional Bootstrap theme.
+
+
+
+## Bugs and feature requests
+
+Have a bug or a feature request? Please first read the [issue guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md#using-the-issue-tracker) and search for existing and closed issues. If your problem or idea is not addressed yet, [please open a new issue](https://github.com/twbs/bootstrap/issues/new).
+
+
+## Documentation
+
+Bootstrap's documentation, included in this repo in the root directory, is built with [Jekyll](http://jekyllrb.com) and publicly hosted on GitHub Pages at <http://getbootstrap.com>. The docs may also be run locally.
+
+### Running documentation locally
+
+1. If necessary, [install Jekyll](http://jekyllrb.com/docs/installation) (requires v1.x).
+ - **Windows users:** Read [this unofficial guide](https://github.com/juthilo/run-jekyll-on-windows/) to get Jekyll up and running without problems. We use Pygments for syntax highlighting, so make sure to read the sections on installing Python and Pygments.
+2. From the root `/bootstrap` directory, run `jekyll serve` in the command line.
+ - **Windows users:** While we use Jekyll's `encoding` setting, you might still need to change the command prompt's character encoding ([code page](http://en.wikipedia.org/wiki/Windows_code_page)) to UTF-8 so Jekyll runs without errors. For Ruby 2.0.0, run `chcp 65001` first. For Ruby 1.9.3, you can alternatively do `SET LANG=en_EN.UTF-8`.
+3. Open <http://localhost:9001> in your browser, and voilà.
+
+Learn more about using Jekyll by reading its [documentation](http://jekyllrb.com/docs/home/).
+
+### Documentation for previous releases
+
+Documentation for v2.3.2 has been made available for the time being at <http://getbootstrap.com/2.3.2/> while folks transition to Bootstrap 3.
+
+[Previous releases](https://github.com/twbs/bootstrap/releases) and their documentation are also available for download.
+
+
+
+## Compiling CSS and JavaScript
+
+Bootstrap uses [Grunt](http://gruntjs.com/) with convenient methods for working with the framework. It's how we compile our code, run tests, and more. To use it, install the required dependencies as directed and then run some Grunt commands.
+
+### Install Grunt
+
+From the command line:
+
+1. Install `grunt-cli` globally with `npm install -g grunt-cli`.
+2. Navigate to the root `/bootstrap` directory, then run `npm install`. npm will look at [package.json](https://github.com/twbs/bootstrap/blob/master/package.json) and automatically install the necessary local dependencies listed there.
+
+When completed, you'll be able to run the various Grunt commands provided from the command line.
+
+**Unfamiliar with `npm`? Don't have node installed?** That's a-okay. npm stands for [node packaged modules](http://npmjs.org/) and is a way to manage development dependencies through node.js. [Download and install node.js](http://nodejs.org/download/) before proceeding.
+
+### Available Grunt commands
+
+#### Build - `grunt`
+Run `grunt` to run tests locally and compile the CSS and JavaScript into `/dist`. **Uses [Less](http://lesscss.org/) and [UglifyJS](http://lisperator.net/uglifyjs/).**
+
+#### Only compile CSS and JavaScript - `grunt dist`
+`grunt dist` creates the `/dist` directory with compiled files. **Uses [Less](http://lesscss.org/) and [UglifyJS](http://lisperator.net/uglifyjs/).**
+
+#### Tests - `grunt test`
+Runs [JSHint](http://jshint.com) and [QUnit](http://qunitjs.com/) tests headlessly in [PhantomJS](http://phantomjs.org/) (used for CI).
+
+#### Watch - `grunt watch`
+This is a convenience method for watching just Less files and automatically building them whenever you save.
+
+### Troubleshooting dependencies
+
+Should you encounter problems with installing dependencies or running Grunt commands, uninstall all previous dependency versions (global and local). Then, rerun `npm install`.
+
+
+
+## Contributing
+
+Please read through our [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development.
+
+Moreover, if your pull request contains JavaScript patches or features, you must include relevant unit tests. All HTML and CSS should conform to the [Code Guide](http://github.com/mdo/code-guide), maintained by [Mark Otto](http://github.com/mdo).
+
+Editor preferences are available in the [editor config](https://github.com/twbs/bootstrap/blob/master/.editorconfig) for easy use in common text editors. Read more and download plugins at <http://editorconfig.org>.
+
+
+
+## Community
+
+Keep track of development and community news.
+
+- Follow [@twbootstrap on Twitter](http://twitter.com/twbootstrap).
+- Read and subscribe to [The Official Bootstrap Blog](http://blog.getbootstrap.com).
+- Chat with fellow Bootstrappers in IRC. On the `irc.freenode.net` server, in the `##twitter-bootstrap` channel.
+- Implementation help may be found at Stack Overflow (tagged [`twitter-bootstrap-3`](http://stackoverflow.com/questions/tagged/twitter-bootstrap-3)).
+
+
+
+
+## Versioning
+
+For transparency into our release cycle and in striving to maintain backward compatibility, Bootstrap is maintained under the Semantic Versioning guidelines. Sometimes we screw up, but we'll adhere to these rules whenever possible.
+
+Releases will be numbered with the following format:
+
+`<major>.<minor>.<patch>`
+
+And constructed with the following guidelines:
+
+- Breaking backward compatibility **bumps the major** while resetting minor and patch
+- New additions without breaking backward compatibility **bumps the minor** while resetting the patch
+- Bug fixes and misc changes **bumps only the patch**
+
+For more information on SemVer, please visit <http://semver.org/>.
+
+
+
+## Authors
+
+**Mark Otto**
+
+- <http://twitter.com/mdo>
+- <http://github.com/mdo>
+
+**Jacob Thornton**
+
+- <http://twitter.com/fat>
+- <http://github.com/fat>
+
+
+
+## Copyright and license
+
+Code and documentation copyright 2011-2014 Twitter, Inc. Code released under [the MIT license](LICENSE). Docs released under [Creative Commons](docs/LICENSE).
diff --git a/bower_components/bootstrap/bower.json b/bower_components/bootstrap/bower.json
new file mode 100644
index 0000000..1961cf2
--- /dev/null
+++ b/bower_components/bootstrap/bower.json
@@ -0,0 +1,24 @@
+{
+ "name": "bootstrap",
+ "version": "3.1.1",
+ "main": [
+ "./dist/css/bootstrap.css",
+ "./dist/js/bootstrap.js",
+ "./dist/fonts/glyphicons-halflings-regular.eot",
+ "./dist/fonts/glyphicons-halflings-regular.svg",
+ "./dist/fonts/glyphicons-halflings-regular.ttf",
+ "./dist/fonts/glyphicons-halflings-regular.woff"
+ ],
+ "ignore": [
+ "**/.*",
+ "_config.yml",
+ "CNAME",
+ "composer.json",
+ "CONTRIBUTING.md",
+ "docs",
+ "js/tests"
+ ],
+ "dependencies": {
+ "jquery": ">= 1.9.0"
+ }
+}
diff --git a/bower_components/bootstrap/dist/css/bootstrap-theme.css b/bower_components/bootstrap/dist/css/bootstrap-theme.css
new file mode 100644
index 0000000..a406992
--- /dev/null
+++ b/bower_components/bootstrap/dist/css/bootstrap-theme.css
@@ -0,0 +1,347 @@
+/*!
+ * Bootstrap v3.1.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+}
+.btn-default:active,
+.btn-primary:active,
+.btn-success:active,
+.btn-info:active,
+.btn-warning:active,
+.btn-danger:active,
+.btn-default.active,
+.btn-primary.active,
+.btn-success.active,
+.btn-info.active,
+.btn-warning.active,
+.btn-danger.active {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn:active,
+.btn.active {
+ background-image: none;
+}
+.btn-default {
+ text-shadow: 0 1px 0 #fff;
+ background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+ background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #dbdbdb;
+ border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus {
+ background-color: #e0e0e0;
+ background-position: 0 -15px;
+}
+.btn-default:active,
+.btn-default.active {
+ background-color: #e0e0e0;
+ border-color: #dbdbdb;
+}
+.btn-primary {
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
+ background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #2b669a;
+}
+.btn-primary:hover,
+.btn-primary:focus {
+ background-color: #2d6ca2;
+ background-position: 0 -15px;
+}
+.btn-primary:active,
+.btn-primary.active {
+ background-color: #2d6ca2;
+ border-color: #2b669a;
+}
+.btn-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #3e8f3e;
+}
+.btn-success:hover,
+.btn-success:focus {
+ background-color: #419641;
+ background-position: 0 -15px;
+}
+.btn-success:active,
+.btn-success.active {
+ background-color: #419641;
+ border-color: #3e8f3e;
+}
+.btn-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #28a4c9;
+}
+.btn-info:hover,
+.btn-info:focus {
+ background-color: #2aabd2;
+ background-position: 0 -15px;
+}
+.btn-info:active,
+.btn-info.active {
+ background-color: #2aabd2;
+ border-color: #28a4c9;
+}
+.btn-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #e38d13;
+}
+.btn-warning:hover,
+.btn-warning:focus {
+ background-color: #eb9316;
+ background-position: 0 -15px;
+}
+.btn-warning:active,
+.btn-warning.active {
+ background-color: #eb9316;
+ border-color: #e38d13;
+}
+.btn-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #b92c28;
+}
+.btn-danger:hover,
+.btn-danger:focus {
+ background-color: #c12e2a;
+ background-position: 0 -15px;
+}
+.btn-danger:active,
+.btn-danger.active {
+ background-color: #c12e2a;
+ border-color: #b92c28;
+}
+.thumbnail,
+.img-thumbnail {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ background-color: #e8e8e8;
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ background-color: #357ebd;
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
+ background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
+ background-repeat: repeat-x;
+}
+.navbar-default {
+ background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+ background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+}
+.navbar-default .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+}
+.navbar-brand,
+.navbar-nav > li > a {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
+}
+.navbar-inverse {
+ background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
+ background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+}
+.navbar-inverse .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%);
+ background-image: linear-gradient(to bottom, #222 0%, #282828 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+}
+.navbar-inverse .navbar-brand,
+.navbar-inverse .navbar-nav > li > a {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
+}
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ border-radius: 0;
+}
+.alert {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+}
+.alert-success {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #b2dba1;
+}
+.alert-info {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #9acfea;
+}
+.alert-warning {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #f5e79e;
+}
+.alert-danger {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+ background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dca7a7;
+}
+.progress {
+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar {
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
+ background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
+ background-repeat: repeat-x;
+}
+.list-group {
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ text-shadow: 0 -1px 0 #3071a9;
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
+ background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #3278b3;
+}
+.panel {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+}
+.panel-default > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-primary > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
+ background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-success > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-info > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-warning > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-danger > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+ background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.well {
+ background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+ background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dcdcdc;
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+}
+/*# sourceMappingURL=bootstrap-theme.css.map */
diff --git a/bower_components/bootstrap/dist/css/bootstrap-theme.css.map b/bower_components/bootstrap/dist/css/bootstrap-theme.css.map
new file mode 100644
index 0000000..b36fc9a
--- /dev/null
+++ b/bower_components/bootstrap/dist/css/bootstrap-theme.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["less/theme.less","less/mixins.less"],"names":[],"mappings":"AAeA;AACA;AACA;AACA;AACA;AACA;EACE,wCAAA;ECoGA,2FAAA;EACQ,mFAAA;;ADhGR,YAAC;AAAD,YAAC;AAAD,YAAC;AAAD,SAAC;AAAD,YAAC;AAAD,WAAC;AACD,YAAC;AAAD,YAAC;AAAD,YAAC;AAAD,SAAC;AAAD,YAAC;AAAD,WAAC;EC8FD,wDAAA;EACQ,gDAAA;;ADnER,IAAC;AACD,IAAC;EACC,sBAAA;;AAKJ;EC4PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;EAyB2C,yBAAA;EAA2B,kBAAA;;AAvBtE,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAeJ;EC2PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAgBJ;EC0PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAiBJ;ECyPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,SAAC;AACD,SAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,SAAC;AACD,SAAC;EACC,yBAAA;EACA,qBAAA;;AAkBJ;ECwPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAmBJ;ECuPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,WAAC;AACD,WAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,WAAC;AACD,WAAC;EACC,yBAAA;EACA,qBAAA;;AA2BJ;AACA;EC6CE,kDAAA;EACQ,0CAAA;;ADpCV,cAAe,KAAK,IAAG;AACvB,cAAe,KAAK,IAAG;ECmOnB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EDpOF,yBAAA;;AAEF,cAAe,UAAU;AACzB,cAAe,UAAU,IAAG;AAC5B,cAAe,UAAU,IAAG;EC6NxB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED9NF,yBAAA;;AAUF;ECiNI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EAoCF,mEAAA;EDrPA,kBAAA;ECaA,2FAAA;EACQ,mFAAA;;ADjBV,eAOE,YAAY,UAAU;EC0MpB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EApMF,wDAAA;EACQ,gDAAA;;ADLV;AACA,WAAY,KAAK;EACf,8CAAA;;AAIF;EC+LI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EAoCF,mEAAA;;ADtOF,eAIE,YAAY,UAAU;EC2LpB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EApMF,uDAAA;EACQ,+CAAA;;ADCV,eASE;AATF,eAUE,YAAY,KAAK;EACf,yCAAA;;AAKJ;AACA;AACA;EACE,gBAAA;;AAUF;EACE,6CAAA;EChCA,0FAAA;EACQ,kFAAA;;AD2CV;ECqJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAKF;ECoJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAMF;ECmJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAOF;ECkJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAgBF;ECyII,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADlIJ;EC+HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADjIJ;EC8HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADhIJ;EC6HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD/HJ;EC4HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD9HJ;EC2HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADtHJ;EACE,kBAAA;EC/EA,kDAAA;EACQ,0CAAA;;ADiFV,gBAAgB;AAChB,gBAAgB,OAAO;AACvB,gBAAgB,OAAO;EACrB,6BAAA;EC4GE,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED7GF,qBAAA;;AAUF;ECjGE,iDAAA;EACQ,yCAAA;;AD0GV,cAAe;ECsFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADxFJ,cAAe;ECqFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADvFJ,cAAe;ECoFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADtFJ,WAAY;ECmFR,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADrFJ,cAAe;ECkFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADpFJ,aAAc;ECiFV,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD5EJ;ECyEI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED1EF,qBAAA;EC1HA,yFAAA;EACQ,iFAAA","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-bg, 5%); @end-color: darken(@navbar-default-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-bg; @end-color: lighten(@navbar-inverse-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n}\n\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","//\n// Mixins\n// --------------------------------------------------\n\n\n// Utilities\n// -------------------------\n\n// Clearfix\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n.clearfix() {\n &:before,\n &:after {\n content: \" \"; // 1\n display: table; // 2\n }\n &:after {\n clear: both;\n }\n}\n\n// WebKit-style focus\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n\n// Center-align a block level element\n.center-block() {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n\n// Sizing shortcuts\n.size(@width; @height) {\n width: @width;\n height: @height;\n}\n.square(@size) {\n .size(@size; @size);\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n &::-moz-placeholder { color: @color; // Firefox\n opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Text overflow\n// Requires inline-block or block for proper styling\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note\n// that we cannot chain the mixins together in Less, so they are repeated.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n\n\n\n// CSS3 PROPERTIES\n// --------------------------------------------------\n\n// Single side border-radius\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support the\n// standard `box-shadow` property.\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Transitions\n.transition(@transition) {\n -webkit-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n// Transformations\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n transform: rotate(@degrees);\n}\n.scale(@ratio; @ratio-y...) {\n -webkit-transform: scale(@ratio, @ratio-y);\n -ms-transform: scale(@ratio, @ratio-y); // IE9 only\n transform: scale(@ratio, @ratio-y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n transform: translate(@x, @y);\n}\n.skew(@x; @y) {\n -webkit-transform: skew(@x, @y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n transform: skew(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// User select\n// For selecting text on the page\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n\n// Resize anything\n.resizable(@direction) {\n resize: @direction; // Options: horizontal, vertical, both\n overflow: auto; // Safari fix\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Opacity\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n\n\n\n// GRADIENTS\n// --------------------------------------------------\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, color-stop(@start-color @start-percent), color-stop(@end-color @end-percent)); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n\n// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n\n\n\n// Retina images\n//\n// Short retina mixin for setting background-image and -size\n\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// COMPONENT MIXINS\n// --------------------------------------------------\n\n// Horizontal dividers\n// -------------------------\n// Dividers (basically an hr) within dropdowns and nav lists\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n\n// Panels\n// -------------------------\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse .panel-body {\n border-top-color: @border;\n }\n }\n & > .panel-footer {\n + .panel-collapse .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n\n// Alerts\n// -------------------------\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n\n// Tables\n// -------------------------\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n\n// List Groups\n// -------------------------\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a& {\n color: @color;\n\n .list-group-item-heading { color: inherit; }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n\n// Button variants\n// -------------------------\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:hover,\n &:focus,\n &:active,\n &.active,\n .open .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 8%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &:active,\n &.active {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n// -------------------------\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n\n// Pagination\n// -------------------------\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n\n// Labels\n// -------------------------\n.label-variant(@color) {\n background-color: @color;\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n\n// Contextual backgrounds\n// -------------------------\n.bg-variant(@color) {\n background-color: @color;\n a&:hover {\n background-color: darken(@color, 10%);\n }\n}\n\n// Typography\n// -------------------------\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover {\n color: darken(@color, 10%);\n }\n}\n\n// Navbar vertical align\n// -------------------------\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n\n// Progress bars\n// -------------------------\n.progress-bar-variant(@color) {\n background-color: @color;\n .progress-striped & {\n #gradient > .striped();\n }\n}\n\n// Responsive utilities\n// -------------------------\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n display: block !important;\n table& { display: table; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n\n\n// Grid System\n// -----------\n\n// Centered container element\n.container-fixed() {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: (@gutter / -2);\n margin-right: (@gutter / -2);\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n @media (min-width: @screen-xs-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-push(@columns) {\n @media (min-width: @screen-xs-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-pull(@columns) {\n @media (min-width: @screen-xs-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n\n// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n border-color: @border-color;\n background-color: @background-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-focus-border` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n"]} \ No newline at end of file
diff --git a/bower_components/bootstrap/dist/css/bootstrap.css.map b/bower_components/bootstrap/dist/css/bootstrap.css.map
new file mode 100644
index 0000000..6bc5a2d
--- /dev/null
+++ b/bower_components/bootstrap/dist/css/bootstrap.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["less/normalize.less","less/print.less","less/scaffolding.less","less/mixins.less","less/variables.less","less/thumbnails.less","less/carousel.less","less/type.less","less/code.less","less/grid.less","less/tables.less","less/forms.less","less/buttons.less","less/button-groups.less","less/component-animations.less","less/glyphicons.less","less/dropdowns.less","less/input-groups.less","less/navs.less","less/navbar.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/pager.less","less/labels.less","less/badges.less","less/jumbotron.less","less/alerts.less","less/progress-bars.less","less/media.less","less/list-group.less","less/panels.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/popovers.less","less/responsive-utilities.less"],"names":[],"mappings":";AAQA;EACE,uBAAA;EACA,0BAAA;EACA,8BAAA;;AAOF;EACE,SAAA;;AAUF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,cAAA;;AAQF;AACA;AACA;AACA;EACE,qBAAA;EACA,wBAAA;;AAQF,KAAK,IAAI;EACP,aAAA;EACA,SAAA;;AAQF;AACA;EACE,aAAA;;AAUF;EACE,uBAAA;;AAOF,CAAC;AACD,CAAC;EACC,UAAA;;AAUF,IAAI;EACF,yBAAA;;AAOF;AACA;EACE,iBAAA;;AAOF;EACE,kBAAA;;AAQF;EACE,cAAA;EACA,gBAAA;;AAOF;EACE,gBAAA;EACA,WAAA;;AAOF;EACE,cAAA;;AAOF;AACA;EACE,cAAA;EACA,cAAA;EACA,kBAAA;EACA,wBAAA;;AAGF;EACE,WAAA;;AAGF;EACE,eAAA;;AAUF;EACE,SAAA;;AAOF,GAAG,IAAI;EACL,gBAAA;;AAUF;EACE,gBAAA;;AAOF;EACE,4BAAA;EACA,uBAAA;EACA,SAAA;;AAOF;EACE,cAAA;;AAOF;AACA;AACA;AACA;EACE,iCAAA;EACA,cAAA;;AAkBF;AACA;AACA;AACA;AACA;EACE,cAAA;EACA,aAAA;EACA,SAAA;;AAOF;EACE,iBAAA;;AAUF;AACA;EACE,oBAAA;;AAWF;AACA,IAAK,MAAK;AACV,KAAK;AACL,KAAK;EACH,0BAAA;EACA,eAAA;;AAOF,MAAM;AACN,IAAK,MAAK;EACR,eAAA;;AAOF,MAAM;AACN,KAAK;EACH,SAAA;EACA,UAAA;;AAQF;EACE,mBAAA;;AAWF,KAAK;AACL,KAAK;EACH,sBAAA;EACA,UAAA;;AASF,KAAK,eAAe;AACpB,KAAK,eAAe;EAClB,YAAA;;AASF,KAAK;EACH,6BAAA;EACA,4BAAA;EACA,+BAAA;EACA,uBAAA;;AASF,KAAK,eAAe;AACpB,KAAK,eAAe;EAClB,wBAAA;;AAOF;EACE,yBAAA;EACA,aAAA;EACA,8BAAA;;AAQF;EACE,SAAA;EACA,UAAA;;AAOF;EACE,cAAA;;AAQF;EACE,iBAAA;;AAUF;EACE,yBAAA;EACA,iBAAA;;AAGF;AACA;EACE,UAAA;;AChUF;EA9FE;IACE,4BAAA;IACA,sBAAA;IACA,kCAAA;IACA,2BAAA;;EAGF;EACA,CAAC;IACC,0BAAA;;EAGF,CAAC,MAAM;IACL,SAAS,KAAK,WAAW,GAAzB;;EAGF,IAAI,OAAO;IACT,SAAS,KAAK,YAAY,GAA1B;;EAIF,CAAC,qBAAqB;EACtB,CAAC,WAAW;IACV,SAAS,EAAT;;EAGF;EACA;IACE,sBAAA;IACA,wBAAA;;EAGF;IACE,2BAAA;;EAGF;EACA;IACE,wBAAA;;EAGF;IACE,0BAAA;;EAGF;EACA;EACA;IACE,UAAA;IACA,SAAA;;EAGF;EACA;IACE,uBAAA;;EAKF;IACE,2BAAA;;EAIF;IACE,aAAA;;EAEF,MACE;EADF,MAEE;IACE,iCAAA;;EAGJ,IAEE;EADF,OAAQ,OACN;IACE,iCAAA;;EAGJ;IACE,sBAAA;;EAGF;IACE,oCAAA;;EAEF,eACE;EADF,eAEE;IACE,iCAAA;;;ACtFN;ECyOE,8BAAA;EACG,2BAAA;EACK,sBAAA;;ADxOV,CAAC;AACD,CAAC;ECqOC,8BAAA;EACG,2BAAA;EACK,sBAAA;;ADhOV;EACE,gBAAA;EACA,6CAAA;;AAGF;EACE,aEcwB,8CFdxB;EACA,eAAA;EACA,uBAAA;EACA,cAAA;EACA,yBAAA;;AAIF;AACA;AACA;AACA;EACE,oBAAA;EACA,kBAAA;EACA,oBAAA;;AAMF;EACE,cAAA;EACA,qBAAA;;AAEA,CAAC;AACD,CAAC;EACC,cAAA;EACA,0BAAA;;AAGF,CAAC;ECzBD,oBAAA;EAEA,0CAAA;EACA,oBAAA;;ADiCF;EACE,SAAA;;AAMF;EACE,sBAAA;;AAIF;AG1EA,UAUE;AAVF,UAWE,EAAE;ACPJ,eAKE,QAME;AAXJ,eAKE,QAOE,IAAI;EHyWN,cAAA;EACA,eAAA;EACA,YAAA;;AD5SF;EACE,kBAAA;;AAMF;EACE,YAAA;EACA,uBAAA;EACA,yBAAA;EACA,yBAAA;EACA,kBAAA;EC8BA,wCAAA;EACQ,gCAAA;EA+PR,qBAAA;EACA,eAAA;EACA,YAAA;;ADxRF;EACE,kBAAA;;AAMF;EACE,gBAAA;EACA,mBAAA;EACA,SAAA;EACA,6BAAA;;AAQF;EACE,kBAAA;EACA,UAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,gBAAA;EACA,MAAM,gBAAN;EACA,SAAA;;AK5HF;AAAI;AAAI;AAAI;AAAI;AAAI;AACpB;AAAK;AAAK;AAAK;AAAK;AAAK;EACvB,oBAAA;EACA,gBAAA;EACA,gBAAA;EACA,cAAA;;AALF,EAOE;AAPE,EAOF;AAPM,EAON;AAPU,EAOV;AAPc,EAOd;AAPkB,EAOlB;AANF,GAME;AANG,GAMH;AANQ,GAMR;AANa,GAMb;AANkB,GAMlB;AANuB,GAMvB;AAPF,EAQE;AARE,EAQF;AARM,EAQN;AARU,EAQV;AARc,EAQd;AARkB,EAQlB;AAPF,GAOE;AAPG,GAOH;AAPQ,GAOR;AAPa,GAOb;AAPkB,GAOlB;AAPuB,GAOvB;EACE,mBAAA;EACA,cAAA;EACA,cAAA;;AAIJ;AAAI;AACJ;AAAI;AACJ;AAAI;EACF,gBAAA;EACA,mBAAA;;AAJF,EAME;AANE,GAMF;AALF,EAKE;AALE,GAKF;AAJF,EAIE;AAJE,GAIF;AANF,EAOE;AAPE,GAOF;AANF,EAME;AANE,GAMF;AALF,EAKE;AALE,GAKF;EACE,cAAA;;AAGJ;AAAI;AACJ;AAAI;AACJ;AAAI;EACF,gBAAA;EACA,mBAAA;;AAJF,EAME;AANE,GAMF;AALF,EAKE;AALE,GAKF;AAJF,EAIE;AAJE,GAIF;AANF,EAOE;AAPE,GAOF;AANF,EAME;AANE,GAMF;AALF,EAKE;AALE,GAKF;EACE,cAAA;;AAIJ;AAAI;EAAM,eAAA;;AACV;AAAI;EAAM,eAAA;;AACV;AAAI;EAAM,eAAA;;AACV;AAAI;EAAM,eAAA;;AACV;AAAI;EAAM,eAAA;;AACV;AAAI;EAAM,eAAA;;AAMV;EACE,gBAAA;;AAGF;EACE,mBAAA;EACA,eAAA;EACA,gBAAA;EACA,gBAAA;;AAKF,QAHqC;EAGrC;IAFI,eAAA;;;AASJ;AACA;EAAU,cAAA;;AAGV;EAAU,kBAAA;;AAGV;EAAuB,gBAAA;;AACvB;EAAuB,iBAAA;;AACvB;EAAuB,kBAAA;;AACvB;EAAuB,mBAAA;;AAGvB;EACE,cAAA;;AAEF;EJofE,cAAA;;AACA,CAAC,aAAC;EACA,cAAA;;AInfJ;EJifE,cAAA;;AACA,CAAC,aAAC;EACA,cAAA;;AIhfJ;EJ8eE,cAAA;;AACA,CAAC,UAAC;EACA,cAAA;;AI7eJ;EJ2eE,cAAA;;AACA,CAAC,aAAC;EACA,cAAA;;AI1eJ;EJweE,cAAA;;AACA,CAAC,YAAC;EACA,cAAA;;AIneJ;EAGE,WAAA;EJqdA,yBAAA;;AACA,CAAC,WAAC;EACA,yBAAA;;AIpdJ;EJkdE,yBAAA;;AACA,CAAC,WAAC;EACA,yBAAA;;AIjdJ;EJ+cE,yBAAA;;AACA,CAAC,QAAC;EACA,yBAAA;;AI9cJ;EJ4cE,yBAAA;;AACA,CAAC,WAAC;EACA,yBAAA;;AI3cJ;EJycE,yBAAA;;AACA,CAAC,UAAC;EACA,yBAAA;;AIncJ;EACE,mBAAA;EACA,mBAAA;EACA,gCAAA;;AAQF;AACA;EACE,aAAA;EACA,mBAAA;;AAHF,EAIE;AAHF,EAGE;AAJF,EAKE;AAJF,EAIE;EACE,gBAAA;;AAOJ;EACE,eAAA;EACA,gBAAA;;AAIF;EALE,eAAA;EACA,gBAAA;EAMA,iBAAA;;AAFF,YAIE;EACE,qBAAA;EACA,iBAAA;EACA,kBAAA;;AAKJ;EACE,aAAA;EACA,mBAAA;;AAEF;AACA;EACE,uBAAA;;AAEF;EACE,iBAAA;;AAEF;EACE,cAAA;;AAwBF,QAhB2C;EACzC,cACE;IACE,WAAA;IACA,YAAA;IACA,WAAA;IACA,iBAAA;IJ1IJ,gBAAA;IACA,uBAAA;IACA,mBAAA;;EImIA,cAQE;IACE,kBAAA;;;AAUN,IAAI;AAEJ,IAAI;EACF,YAAA;EACA,iCAAA;;AAEF;EACE,cAAA;EACA,yBAAA;;AAIF;EACE,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,8BAAA;;AAKE,UAHF,EAGG;AAAD,UAFF,GAEG;AAAD,UADF,GACG;EACC,gBAAA;;AAVN,UAgBE;AAhBF,UAiBE;AAjBF,UAkBE;EACE,cAAA;EACA,cAAA;EACA,uBAAA;EACA,cAAA;;AAEA,UARF,OAQG;AAAD,UAPF,MAOG;AAAD,UANF,OAMG;EACC,SAAS,aAAT;;AAQN;AACA,UAAU;EACR,mBAAA;EACA,eAAA;EACA,+BAAA;EACA,cAAA;EACA,iBAAA;;AAME,mBAHF,OAGG;AAAD,UAXM,WAQR,OAGG;AAAD,mBAFF,MAEG;AAAD,UAXM,WASR,MAEG;AAAD,mBADF,OACG;AAAD,UAXM,WAUR,OACG;EAAU,SAAS,EAAT;;AACX,mBAJF,OAIG;AAAD,UAZM,WAQR,OAIG;AAAD,mBAHF,MAGG;AAAD,UAZM,WASR,MAGG;AAAD,mBAFF,OAEG;AAAD,UAZM,WAUR,OAEG;EACC,SAAS,aAAT;;AAMN,UAAU;AACV,UAAU;EACR,SAAS,EAAT;;AAIF;EACE,mBAAA;EACA,kBAAA;EACA,uBAAA;;AC7RF;AACA;AACA;AACA;EACE,sCJkCiD,wBIlCjD;;AAIF;EACE,gBAAA;EACA,cAAA;EACA,cAAA;EACA,yBAAA;EACA,mBAAA;EACA,kBAAA;;AAIF;EACE,gBAAA;EACA,cAAA;EACA,cAAA;EACA,yBAAA;EACA,kBAAA;EACA,8CAAA;;AAIF;EACE,cAAA;EACA,cAAA;EACA,gBAAA;EACA,eAAA;EACA,uBAAA;EACA,qBAAA;EACA,qBAAA;EACA,cAAA;EACA,yBAAA;EACA,yBAAA;EACA,kBAAA;;AAXF,GAcE;EACE,UAAA;EACA,kBAAA;EACA,cAAA;EACA,qBAAA;EACA,6BAAA;EACA,gBAAA;;AAKJ;EACE,iBAAA;EACA,kBAAA;;ACpDF;ENqnBE,kBAAA;EACA,iBAAA;EACA,kBAAA;EACA,mBAAA;;AMlnBA,QAHmC;EAGnC;IAFE,YAAA;;;AAKF,QAHmC;EAGnC;IAFE,YAAA;;;AAKJ,QAHqC;EAGrC;IAFI,aAAA;;;AAUJ;ENimBE,kBAAA;EACA,iBAAA;EACA,kBAAA;EACA,mBAAA;;AM3lBF;ENimBE,kBAAA;EACA,mBAAA;;AAqIE;EACE,kBAAA;EAEA,eAAA;EAEA,kBAAA;EACA,mBAAA;;AAgBF;EACE,WAAA;;AAOJ,KAAK,EAAQ,CAAC;EACZ,WAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,mBAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,mBAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,UAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,mBAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,mBAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,UAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,mBAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,mBAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,UAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,mBAAA;;AADF,KAAK,EAAQ,CAAC;EACZ,kBAAA;;AASF,KAAK,EAAQ,MAAM;EACjB,WAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,mBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,mBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,UAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,mBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,mBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,UAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,mBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,mBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,UAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,mBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,kBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,SAAA;;AANF,KAAK,EAAQ,MAAM;EACjB,UAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,kBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,kBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,SAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,kBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,kBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,SAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,kBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,kBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,SAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,kBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,iBAAA;;AADF,KAAK,EAAQ,MAAM;EACjB,QAAA;;AASF,KAAK,EAAQ,QAAQ;EACnB,iBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,yBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,yBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,gBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,yBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,yBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,gBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,yBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,yBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,gBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,yBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,wBAAA;;AADF,KAAK,EAAQ,QAAQ;EACnB,eAAA;;AMvvBJ,QALmC;ENouB/B;IACE,WAAA;;EAOJ,KAAK,EAAQ,CAAC;IACZ,WAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,UAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,UAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,UAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,kBAAA;;EASF,KAAK,EAAQ,MAAM;IACjB,WAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EANF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,iBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,QAAA;;EASF,KAAK,EAAQ,QAAQ;IACnB,iBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,gBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,gBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,gBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,wBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,eAAA;;;AM9uBJ,QALmC;EN2tB/B;IACE,WAAA;;EAOJ,KAAK,EAAQ,CAAC;IACZ,WAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,UAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,UAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,UAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,kBAAA;;EASF,KAAK,EAAQ,MAAM;IACjB,WAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EANF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,iBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,QAAA;;EASF,KAAK,EAAQ,QAAQ;IACnB,iBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,gBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,gBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,gBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,wBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,eAAA;;;AMvuBJ,QAHmC;ENktB/B;IACE,WAAA;;EAOJ,KAAK,EAAQ,CAAC;IACZ,WAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,UAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,UAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,UAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,mBAAA;;EADF,KAAK,EAAQ,CAAC;IACZ,kBAAA;;EASF,KAAK,EAAQ,MAAM;IACjB,WAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,mBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EANF,KAAK,EAAQ,MAAM;IACjB,UAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,SAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,kBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,iBAAA;;EADF,KAAK,EAAQ,MAAM;IACjB,QAAA;;EASF,KAAK,EAAQ,QAAQ;IACnB,iBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,gBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,gBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,gBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,yBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,wBAAA;;EADF,KAAK,EAAQ,QAAQ;IACnB,eAAA;;;AOtzBJ;EACE,eAAA;EACA,6BAAA;;AAEF;EACE,gBAAA;;AAMF;EACE,WAAA;EACA,mBAAA;;AAFF,MAIE,QAGE,KACE;AARN,MAKE,QAEE,KACE;AARN,MAME,QACE,KACE;AARN,MAIE,QAGE,KAEE;AATN,MAKE,QAEE,KAEE;AATN,MAME,QACE,KAEE;EACE,YAAA;EACA,uBAAA;EACA,mBAAA;EACA,6BAAA;;AAbR,MAkBE,QAAQ,KAAK;EACX,sBAAA;EACA,gCAAA;;AApBJ,MAuBE,UAAU,QAGR,KAAI,YACF;AA3BN,MAwBE,WAAW,QAET,KAAI,YACF;AA3BN,MAyBE,QAAO,YACL,KAAI,YACF;AA3BN,MAuBE,UAAU,QAGR,KAAI,YAEF;AA5BN,MAwBE,WAAW,QAET,KAAI,YAEF;AA5BN,MAyBE,QAAO,YACL,KAAI,YAEF;EACE,aAAA;;AA7BR,MAkCE,QAAQ;EACN,6BAAA;;AAnCJ,MAuCE;EACE,yBAAA;;AAOJ,gBACE,QAGE,KACE;AALN,gBAEE,QAEE,KACE;AALN,gBAGE,QACE,KACE;AALN,gBACE,QAGE,KAEE;AANN,gBAEE,QAEE,KAEE;AANN,gBAGE,QACE,KAEE;EACE,YAAA;;AAWR;EACE,yBAAA;;AADF,eAEE,QAGE,KACE;AANN,eAGE,QAEE,KACE;AANN,eAIE,QACE,KACE;AANN,eAEE,QAGE,KAEE;AAPN,eAGE,QAEE,KAEE;AAPN,eAIE,QACE,KAEE;EACE,yBAAA;;AARR,eAYE,QAAQ,KACN;AAbJ,eAYE,QAAQ,KAEN;EACE,wBAAA;;AAUN,cACE,QAAQ,KAAI,UAAU,KACpB;AAFJ,cACE,QAAQ,KAAI,UAAU,KAEpB;EACE,yBAAA;;AAUN,YACE,QAAQ,KAAI,MACV;AAFJ,YACE,QAAQ,KAAI,MAEV;EACE,yBAAA;;AAUN,KAAM,IAAG;EACP,gBAAA;EACA,WAAA;EACA,qBAAA;;AAKE,KAFF,GAEG;AAAD,KADF,GACG;EACC,gBAAA;EACA,WAAA;EACA,mBAAA;;AP0SJ,MAAO,QAAQ,KAGb,KAAI,CAAC;AAFP,MAAO,QAAQ,KAEb,KAAI,CAAC;AADP,MAAO,QAAQ,KACb,KAAI,CAAC;AAHP,MAAO,QAAQ,KAIb,KAAI,CAAC;AAHP,MAAO,QAAQ,KAGb,KAAI,CAAC;AAFP,MAAO,QAAQ,KAEb,KAAI,CAAC;AACL,MALK,QAAQ,KAKZ,CAAC,MAAS;AAAX,MAJK,QAAQ,KAIZ,CAAC,MAAS;AAAX,MAHK,QAAQ,KAGZ,CAAC,MAAS;AACX,MANK,QAAQ,KAMZ,CAAC,MAAS;AAAX,MALK,QAAQ,KAKZ,CAAC,MAAS;AAAX,MAJK,QAAQ,KAIZ,CAAC,MAAS;EACT,yBAAA;;AAMJ,YAAa,QAAQ,KACnB,KAAI,CAAC,MAAQ;AADf,YAAa,QAAQ,KAEnB,KAAI,CAAC,MAAQ;AACb,YAHW,QAAQ,KAGlB,CAAC,MAAQ,MAAO;AACjB,YAJW,QAAQ,KAIlB,CAAC,MAAQ,MAAO;EACf,yBAAA;;AAlBJ,MAAO,QAAQ,KAGb,KAAI,CAAC;AAFP,MAAO,QAAQ,KAEb,KAAI,CAAC;AADP,MAAO,QAAQ,KACb,KAAI,CAAC;AAHP,MAAO,QAAQ,KAIb,KAAI,CAAC;AAHP,MAAO,QAAQ,KAGb,KAAI,CAAC;AAFP,MAAO,QAAQ,KAEb,KAAI,CAAC;AACL,MALK,QAAQ,KAKZ,CAAC,OAAS;AAAX,MAJK,QAAQ,KAIZ,CAAC,OAAS;AAAX,MAHK,QAAQ,KAGZ,CAAC,OAAS;AACX,MANK,QAAQ,KAMZ,CAAC,OAAS;AAAX,MALK,QAAQ,KAKZ,CAAC,OAAS;AAAX,MAJK,QAAQ,KAIZ,CAAC,OAAS;EACT,yBAAA;;AAMJ,YAAa,QAAQ,KACnB,KAAI,CAAC,OAAQ;AADf,YAAa,QAAQ,KAEnB,KAAI,CAAC,OAAQ;AACb,YAHW,QAAQ,KAGlB,CAAC,OAAQ,MAAO;AACjB,YAJW,QAAQ,KAIlB,CAAC,OAAQ,MAAO;EACf,yBAAA;;AAlBJ,MAAO,QAAQ,KAGb,KAAI,CAAC;AAFP,MAAO,QAAQ,KAEb,KAAI,CAAC;AADP,MAAO,QAAQ,KACb,KAAI,CAAC;AAHP,MAAO,QAAQ,KAIb,KAAI,CAAC;AAHP,MAAO,QAAQ,KAGb,KAAI,CAAC;AAFP,MAAO,QAAQ,KAEb,KAAI,CAAC;AACL,MALK,QAAQ,KAKZ,CAAC,IAAS;AAAX,MAJK,QAAQ,KAIZ,CAAC,IAAS;AAAX,MAHK,QAAQ,KAGZ,CAAC,IAAS;AACX,MANK,QAAQ,KAMZ,CAAC,IAAS;AAAX,MALK,QAAQ,KAKZ,CAAC,IAAS;AAAX,MAJK,QAAQ,KAIZ,CAAC,IAAS;EACT,yBAAA;;AAMJ,YAAa,QAAQ,KACnB,KAAI,CAAC,IAAQ;AADf,YAAa,QAAQ,KAEnB,KAAI,CAAC,IAAQ;AACb,YAHW,QAAQ,KAGlB,CAAC,IAAQ,MAAO;AACjB,YAJW,QAAQ,KAIlB,CAAC,IAAQ,MAAO;EACf,yBAAA;;AAlBJ,MAAO,QAAQ,KAGb,KAAI,CAAC;AAFP,MAAO,QAAQ,KAEb,KAAI,CAAC;AADP,MAAO,QAAQ,KACb,KAAI,CAAC;AAHP,MAAO,QAAQ,KAIb,KAAI,CAAC;AAHP,MAAO,QAAQ,KAGb,KAAI,CAAC;AAFP,MAAO,QAAQ,KAEb,KAAI,CAAC;AACL,MALK,QAAQ,KAKZ,CAAC,OAAS;AAAX,MAJK,QAAQ,KAIZ,CAAC,OAAS;AAAX,MAHK,QAAQ,KAGZ,CAAC,OAAS;AACX,MANK,QAAQ,KAMZ,CAAC,OAAS;AAAX,MALK,QAAQ,KAKZ,CAAC,OAAS;AAAX,MAJK,QAAQ,KAIZ,CAAC,OAAS;EACT,yBAAA;;AAMJ,YAAa,QAAQ,KACnB,KAAI,CAAC,OAAQ;AADf,YAAa,QAAQ,KAEnB,KAAI,CAAC,OAAQ;AACb,YAHW,QAAQ,KAGlB,CAAC,OAAQ,MAAO;AACjB,YAJW,QAAQ,KAIlB,CAAC,OAAQ,MAAO;EACf,yBAAA;;AAlBJ,MAAO,QAAQ,KAGb,KAAI,CAAC;AAFP,MAAO,QAAQ,KAEb,KAAI,CAAC;AADP,MAAO,QAAQ,KACb,KAAI,CAAC;AAHP,MAAO,QAAQ,KAIb,KAAI,CAAC;AAHP,MAAO,QAAQ,KAGb,KAAI,CAAC;AAFP,MAAO,QAAQ,KAEb,KAAI,CAAC;AACL,MALK,QAAQ,KAKZ,CAAC,MAAS;AAAX,MAJK,QAAQ,KAIZ,CAAC,MAAS;AAAX,MAHK,QAAQ,KAGZ,CAAC,MAAS;AACX,MANK,QAAQ,KAMZ,CAAC,MAAS;AAAX,MALK,QAAQ,KAKZ,CAAC,MAAS;AAAX,MAJK,QAAQ,KAIZ,CAAC,MAAS;EACT,yBAAA;;AAMJ,YAAa,QAAQ,KACnB,KAAI,CAAC,MAAQ;AADf,YAAa,QAAQ,KAEnB,KAAI,CAAC,MAAQ;AACb,YAHW,QAAQ,KAGlB,CAAC,MAAQ,MAAO;AACjB,YAJW,QAAQ,KAIlB,CAAC,MAAQ,MAAO;EACf,yBAAA;;AOpON,QA/DmC;EACjC;IACE,WAAA;IACA,mBAAA;IACA,kBAAA;IACA,kBAAA;IACA,4CAAA;IACA,yBAAA;IACA,iCAAA;;EAPF,iBAUE;IACE,gBAAA;;EAXJ,iBAUE,SAIE,QAGE,KACE;EAlBR,iBAUE,SAKE,QAEE,KACE;EAlBR,iBAUE,SAME,QACE,KACE;EAlBR,iBAUE,SAIE,QAGE,KAEE;EAnBR,iBAUE,SAKE,QAEE,KAEE;EAnBR,iBAUE,SAME,QACE,KAEE;IACE,mBAAA;;EApBV,iBA2BE;IACE,SAAA;;EA5BJ,iBA2BE,kBAIE,QAGE,KACE,KAAI;EAnCZ,iBA2BE,kBAKE,QAEE,KACE,KAAI;EAnCZ,iBA2BE,kBAME,QACE,KACE,KAAI;EAnCZ,iBA2BE,kBAIE,QAGE,KAEE,KAAI;EApCZ,iBA2BE,kBAKE,QAEE,KAEE,KAAI;EApCZ,iBA2BE,kBAME,QACE,KAEE,KAAI;IACF,cAAA;;EArCV,iBA2BE,kBAIE,QAGE,KAKE,KAAI;EAvCZ,iBA2BE,kBAKE,QAEE,KAKE,KAAI;EAvCZ,iBA2BE,kBAME,QACE,KAKE,KAAI;EAvCZ,iBA2BE,kBAIE,QAGE,KAME,KAAI;EAxCZ,iBA2BE,kBAKE,QAEE,KAME,KAAI;EAxCZ,iBA2BE,kBAME,QACE,KAME,KAAI;IACF,eAAA;;EAzCV,iBA2BE,kBAsBE,QAEE,KAAI,WACF;EApDR,iBA2BE,kBAuBE,QACE,KAAI,WACF;EApDR,iBA2BE,kBAsBE,QAEE,KAAI,WAEF;EArDR,iBA2BE,kBAuBE,QACE,KAAI,WAEF;IACE,gBAAA;;;ACxNZ;EACE,UAAA;EACA,SAAA;EACA,SAAA;EAIA,YAAA;;AAGF;EACE,cAAA;EACA,WAAA;EACA,UAAA;EACA,mBAAA;EACA,eAAA;EACA,oBAAA;EACA,cAAA;EACA,SAAA;EACA,gCAAA;;AAGF;EACE,qBAAA;EACA,kBAAA;EACA,iBAAA;;AAWF,KAAK;ERsMH,8BAAA;EACG,2BAAA;EACK,sBAAA;;AQnMV,KAAK;AACL,KAAK;EACH,eAAA;EACA,kBAAA;;EACA,mBAAA;;AAIF,KAAK;EACH,cAAA;;AAIF,KAAK;EACH,cAAA;EACA,WAAA;;AAIF,MAAM;AACN,MAAM;EACJ,YAAA;;AAIF,KAAK,aAAa;AAClB,KAAK,cAAc;AACnB,KAAK,iBAAiB;ER7CpB,oBAAA;EAEA,0CAAA;EACA,oBAAA;;AQ+CF;EACE,cAAA;EACA,gBAAA;EACA,eAAA;EACA,uBAAA;EACA,cAAA;;AA0BF;EACE,cAAA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;EACA,eAAA;EACA,uBAAA;EACA,cAAA;EACA,yBAAA;EACA,sBAAA;EACA,yBAAA;EACA,kBAAA;ERHA,wDAAA;EACQ,gDAAA;EAKR,8EAAA;EACQ,sEAAA;;AAmwBR,aAAC;EACC,qBAAA;EACA,UAAA;EA5wBF,sFAAA;EACQ,8EAAA;;AAlER,aAAC;EAA+B,cAAA;EACA,UAAA;;AAChC,aAAC;EAA+B,cAAA;;AAChC,aAAC;EAA+B,cAAA;;AQgFhC,aAAC;AACD,aAAC;AACD,QAAQ,UAAW;EACjB,mBAAA;EACA,yBAAA;EACA,UAAA;;AAIF,QAAQ;EACN,YAAA;;AAYJ,KAAK;EACH,wBAAA;;AASF,KAAK;EACH,iBAAA;;AASF;EACE,mBAAA;;AAQF;AACA;EACE,cAAA;EACA,gBAAA;EACA,gBAAA;EACA,mBAAA;EACA,kBAAA;;AANF,MAOE;AANF,SAME;EACE,eAAA;EACA,mBAAA;EACA,eAAA;;AAGJ,MAAO,MAAK;AACZ,aAAc,MAAK;AACnB,SAAU,MAAK;AACf,gBAAiB,MAAK;EACpB,WAAA;EACA,kBAAA;;AAEF,MAAO;AACP,SAAU;EACR,gBAAA;;AAIF;AACA;EACE,qBAAA;EACA,kBAAA;EACA,gBAAA;EACA,sBAAA;EACA,mBAAA;EACA,eAAA;;AAEF,aAAc;AACd,gBAAiB;EACf,aAAA;EACA,iBAAA;;AAYA,KANG,cAMF;AAAD,KALG,iBAKF;AAAD,MAAC;AAAD,aAAC;AAAD,SAAC;AAAD,gBAAC;AACD,QAAQ,UAAW,MAPhB;AAOH,QAAQ,UAAW,MANhB;AAMH,QAAQ,UAAW;AAAnB,QAAQ,UAAW;AAAnB,QAAQ,UAAW;AAAnB,QAAQ,UAAW;EACjB,mBAAA;;AAUJ;ERqpBE,YAAA;EACA,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,kBAAA;;AAEA,MAAM;EACJ,YAAA;EACA,iBAAA;;AAGF,QAAQ;AACR,MAAM,UAAU;EACd,YAAA;;AQ9pBJ;ERipBE,YAAA;EACA,kBAAA;EACA,eAAA;EACA,iBAAA;EACA,kBAAA;;AAEA,MAAM;EACJ,YAAA;EACA,iBAAA;;AAGF,QAAQ;AACR,MAAM,UAAU;EACd,YAAA;;AQrpBJ;EAEE,kBAAA;;AAFF,aAKE;EACE,qBAAA;;AANJ,aAUE;EACE,kBAAA;EACA,SAAA;EACA,QAAA;EACA,cAAA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;EACA,kBAAA;;AAKJ,YRsjBE;AQtjBF,YRujBE;AQvjBF,YRwjBE;AQxjBF,YRyjBE;AQzjBF,YR0jBE;AQ1jBF,YR2jBE;EACE,cAAA;;AQ5jBJ,YR+jBE;EACE,qBAAA;EAvuBF,wDAAA;EACQ,gDAAA;;AAwuBN,YAHF,cAGG;EACC,qBAAA;EA1uBJ,yEAAA;EACQ,iEAAA;;AQsKV,YRykBE;EACE,cAAA;EACA,qBAAA;EACA,yBAAA;;AQ5kBJ,YR+kBE;EACE,cAAA;;AQ7kBJ,YRmjBE;AQnjBF,YRojBE;AQpjBF,YRqjBE;AQrjBF,YRsjBE;AQtjBF,YRujBE;AQvjBF,YRwjBE;EACE,cAAA;;AQzjBJ,YR4jBE;EACE,qBAAA;EAvuBF,wDAAA;EACQ,gDAAA;;AAwuBN,YAHF,cAGG;EACC,qBAAA;EA1uBJ,yEAAA;EACQ,iEAAA;;AQyKV,YRskBE;EACE,cAAA;EACA,qBAAA;EACA,yBAAA;;AQzkBJ,YR4kBE;EACE,cAAA;;AQ1kBJ,URgjBE;AQhjBF,URijBE;AQjjBF,URkjBE;AQljBF,URmjBE;AQnjBF,URojBE;AQpjBF,URqjBE;EACE,cAAA;;AQtjBJ,URyjBE;EACE,qBAAA;EAvuBF,wDAAA;EACQ,gDAAA;;AAwuBN,UAHF,cAGG;EACC,qBAAA;EA1uBJ,yEAAA;EACQ,iEAAA;;AQ4KV,URmkBE;EACE,cAAA;EACA,qBAAA;EACA,yBAAA;;AQtkBJ,URykBE;EACE,cAAA;;AQhkBJ;EACE,gBAAA;;AASF;EACE,cAAA;EACA,eAAA;EACA,mBAAA;EACA,cAAA;;AAoEF,QAjDqC;EAiDrC,YA/CI;IACE,qBAAA;IACA,gBAAA;IACA,sBAAA;;EA4CN,YAxCI;IACE,qBAAA;IACA,WAAA;IACA,sBAAA;;EAqCN,YAlCI,aAAa;IACX,WAAA;;EAiCN,YA9BI;IACE,gBAAA;IACA,sBAAA;;EA4BN,YAtBI;EAsBJ,YArBI;IACE,qBAAA;IACA,aAAA;IACA,gBAAA;IACA,eAAA;IACA,sBAAA;;EAgBN,YAdI,OAAO,MAAK;EAchB,YAbI,UAAU,MAAK;IACb,WAAA;IACA,cAAA;;EAWN,YAJI,cAAc;IACZ,MAAA;;;AAWN,gBAGE;AAHF,gBAIE;AAJF,gBAKE;AALF,gBAME;AANF,gBAOE;EACE,aAAA;EACA,gBAAA;EACA,gBAAA;;AAVJ,gBAcE;AAdF,gBAeE;EACE,gBAAA;;AAhBJ,gBAoBE;ERyOA,kBAAA;EACA,mBAAA;;AQ9PF,gBAwBE;EACE,gBAAA;;AAUF,QANmC;EAMnC,gBALE;IACE,iBAAA;;;AA/BN,gBAuCE,cAAc;EACZ,MAAA;EACA,WAAA;;AC3aJ;EACE,qBAAA;EACA,gBAAA;EACA,mBAAA;EACA,kBAAA;EACA,sBAAA;EACA,eAAA;EACA,sBAAA;EACA,6BAAA;EACA,mBAAA;ET0gBA,iBAAA;EACA,eAAA;EACA,uBAAA;EACA,kBAAA;EAnSA,yBAAA;EACG,sBAAA;EACC,qBAAA;EACI,iBAAA;;AStON,IAAC;AAAD,IAFD,OAEE;AAAD,IADD,OACE;ETQH,oBAAA;EAEA,0CAAA;EACA,oBAAA;;ASNA,IAAC;AACD,IAAC;EACC,cAAA;EACA,qBAAA;;AAGF,IAAC;AACD,IAAC;EACC,UAAA;EACA,sBAAA;ETmFF,wDAAA;EACQ,gDAAA;;AShFR,IAAC;AACD,IAAC;AACD,QAAQ,UAAW;EACjB,mBAAA;EACA,oBAAA;ET+OF,aAAA;EAGA,yBAAA;EAvKA,wBAAA;EACQ,gBAAA;;ASlEV;ET2bE,cAAA;EACA,yBAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;AACD,YAAC;AACD,YAAC;AACD,KAAM,iBAAgB;EACpB,cAAA;EACA,yBAAA;EACI,qBAAA;;AAEN,YAAC;AACD,YAAC;AACD,KAAM,iBAAgB;EACpB,sBAAA;;AAKA,YAHD;AAGC,YAFD;AAEC,QADM,UAAW;AAEjB,YAJD,SAIE;AAAD,YAHD,UAGE;AAAD,QAFM,UAAW,aAEhB;AACD,YALD,SAKE;AAAD,YAJD,UAIE;AAAD,QAHM,UAAW,aAGhB;AACD,YAND,SAME;AAAD,YALD,UAKE;AAAD,QAJM,UAAW,aAIhB;AACD,YAPD,SAOE;AAAD,YAND,UAME;AAAD,QALM,UAAW,aAKhB;EACC,yBAAA;EACI,qBAAA;;AStdV,YT0dE;EACE,cAAA;EACA,yBAAA;;ASzdJ;ETwbE,cAAA;EACA,yBAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;AACD,YAAC;AACD,YAAC;AACD,KAAM,iBAAgB;EACpB,cAAA;EACA,yBAAA;EACI,qBAAA;;AAEN,YAAC;AACD,YAAC;AACD,KAAM,iBAAgB;EACpB,sBAAA;;AAKA,YAHD;AAGC,YAFD;AAEC,QADM,UAAW;AAEjB,YAJD,SAIE;AAAD,YAHD,UAGE;AAAD,QAFM,UAAW,aAEhB;AACD,YALD,SAKE;AAAD,YAJD,UAIE;AAAD,QAHM,UAAW,aAGhB;AACD,YAND,SAME;AAAD,YALD,UAKE;AAAD,QAJM,UAAW,aAIhB;AACD,YAPD,SAOE;AAAD,YAND,UAME;AAAD,QALM,UAAW,aAKhB;EACC,yBAAA;EACI,qBAAA;;ASndV,YTudE;EACE,cAAA;EACA,yBAAA;;ASrdJ;ETobE,cAAA;EACA,yBAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;AACD,YAAC;AACD,YAAC;AACD,KAAM,iBAAgB;EACpB,cAAA;EACA,yBAAA;EACI,qBAAA;;AAEN,YAAC;AACD,YAAC;AACD,KAAM,iBAAgB;EACpB,sBAAA;;AAKA,YAHD;AAGC,YAFD;AAEC,QADM,UAAW;AAEjB,YAJD,SAIE;AAAD,YAHD,UAGE;AAAD,QAFM,UAAW,aAEhB;AACD,YALD,SAKE;AAAD,YAJD,UAIE;AAAD,QAHM,UAAW,aAGhB;AACD,YAND,SAME;AAAD,YALD,UAKE;AAAD,QAJM,UAAW,aAIhB;AACD,YAPD,SAOE;AAAD,YAND,UAME;AAAD,QALM,UAAW,aAKhB;EACC,yBAAA;EACI,qBAAA;;AS/cV,YTmdE;EACE,cAAA;EACA,yBAAA;;ASjdJ;ETgbE,cAAA;EACA,yBAAA;EACA,qBAAA;;AAEA,SAAC;AACD,SAAC;AACD,SAAC;AACD,SAAC;AACD,KAAM,iBAAgB;EACpB,cAAA;EACA,yBAAA;EACI,qBAAA;;AAEN,SAAC;AACD,SAAC;AACD,KAAM,iBAAgB;EACpB,sBAAA;;AAKA,SAHD;AAGC,SAFD;AAEC,QADM,UAAW;AAEjB,SAJD,SAIE;AAAD,SAHD,UAGE;AAAD,QAFM,UAAW,UAEhB;AACD,SALD,SAKE;AAAD,SAJD,UAIE;AAAD,QAHM,UAAW,UAGhB;AACD,SAND,SAME;AAAD,SALD,UAKE;AAAD,QAJM,UAAW,UAIhB;AACD,SAPD,SAOE;AAAD,SAND,UAME;AAAD,QALM,UAAW,UAKhB;EACC,yBAAA;EACI,qBAAA;;AS3cV,ST+cE;EACE,cAAA;EACA,yBAAA;;AS7cJ;ET4aE,cAAA;EACA,yBAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;AACD,YAAC;AACD,YAAC;AACD,KAAM,iBAAgB;EACpB,cAAA;EACA,yBAAA;EACI,qBAAA;;AAEN,YAAC;AACD,YAAC;AACD,KAAM,iBAAgB;EACpB,sBAAA;;AAKA,YAHD;AAGC,YAFD;AAEC,QADM,UAAW;AAEjB,YAJD,SAIE;AAAD,YAHD,UAGE;AAAD,QAFM,UAAW,aAEhB;AACD,YALD,SAKE;AAAD,YAJD,UAIE;AAAD,QAHM,UAAW,aAGhB;AACD,YAND,SAME;AAAD,YALD,UAKE;AAAD,QAJM,UAAW,aAIhB;AACD,YAPD,SAOE;AAAD,YAND,UAME;AAAD,QALM,UAAW,aAKhB;EACC,yBAAA;EACI,qBAAA;;ASvcV,YT2cE;EACE,cAAA;EACA,yBAAA;;ASzcJ;ETwaE,cAAA;EACA,yBAAA;EACA,qBAAA;;AAEA,WAAC;AACD,WAAC;AACD,WAAC;AACD,WAAC;AACD,KAAM,iBAAgB;EACpB,cAAA;EACA,yBAAA;EACI,qBAAA;;AAEN,WAAC;AACD,WAAC;AACD,KAAM,iBAAgB;EACpB,sBAAA;;AAKA,WAHD;AAGC,WAFD;AAEC,QADM,UAAW;AAEjB,WAJD,SAIE;AAAD,WAHD,UAGE;AAAD,QAFM,UAAW,YAEhB;AACD,WALD,SAKE;AAAD,WAJD,UAIE;AAAD,QAHM,UAAW,YAGhB;AACD,WAND,SAME;AAAD,WALD,UAKE;AAAD,QAJM,UAAW,YAIhB;AACD,WAPD,SAOE;AAAD,WAND,UAME;AAAD,QALM,UAAW,YAKhB;EACC,yBAAA;EACI,qBAAA;;ASncV,WTucE;EACE,cAAA;EACA,yBAAA;;AShcJ;EACE,cAAA;EACA,mBAAA;EACA,eAAA;EACA,gBAAA;;AAEA;AACA,SAAC;AACD,SAAC;AACD,QAAQ,UAAW;EACjB,6BAAA;ET2BF,wBAAA;EACQ,gBAAA;;ASzBR;AACA,SAAC;AACD,SAAC;AACD,SAAC;EACC,yBAAA;;AAEF,SAAC;AACD,SAAC;EACC,cAAA;EACA,0BAAA;EACA,6BAAA;;AAIA,SAFD,UAEE;AAAD,QADM,UAAW,UAChB;AACD,SAHD,UAGE;AAAD,QAFM,UAAW,UAEhB;EACC,cAAA;EACA,qBAAA;;AASN;ACvBA,aAAc;EVubZ,kBAAA;EACA,eAAA;EACA,iBAAA;EACA,kBAAA;;AS/ZF;AC5BA,aAAc;EVwbZ,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,kBAAA;;AS3ZF;ACjCA,aAAc;EVybZ,gBAAA;EACA,eAAA;EACA,gBAAA;EACA,kBAAA;;ASnZF;EACE,cAAA;EACA,WAAA;EACA,eAAA;EACA,gBAAA;;AAIF,UAAW;EACT,eAAA;;AAOA,KAHG,eAGF;AAAD,KAFG,cAEF;AAAD,KADG,eACF;EACC,WAAA;;AEnJJ;EACE,UAAA;EXqHA,wCAAA;EACQ,gCAAA;;AWpHR,KAAC;EACC,UAAA;;AAIJ;EACE,aAAA;;AACA,SAAC;EACC,cAAA;;AAGJ;EACE,kBAAA;EACA,SAAA;EACA,gBAAA;EXqGA,qCAAA;EACQ,6BAAA;;AYtHV;EACE,aAAa,sBAAb;EACA,qDAAA;EACA,2TAAA;;AAOF;EACE,kBAAA;EACA,QAAA;EACA,qBAAA;EACA,aAAa,sBAAb;EACA,kBAAA;EACA,mBAAA;EACA,cAAA;EACA,mCAAA;EACA,kCAAA;;AAIkC,mBAAC;EAAU,SAAS,KAAT;;AACX,eAAC;EAAU,SAAS,KAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,aAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,aAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,cAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,cAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,cAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,wBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,yBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,wBAAC;EAAU,SAAS,OAAT;;AACX,wBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,wBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,wBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,wBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,2BAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,wBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,0BAAC;EAAU,SAAS,OAAT;;AACX,4BAAC;EAAU,SAAS,OAAT;;AACX,cAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,6BAAC;EAAU,SAAS,OAAT;;AACX,4BAAC;EAAU,SAAS,OAAT;;AACX,0BAAC;EAAU,SAAS,OAAT;;AACX,4BAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,cAAC;EAAU,SAAS,OAAT;;AACX,cAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,2BAAC;EAAU,SAAS,OAAT;;AACX,+BAAC;EAAU,SAAS,OAAT;;AACX,wBAAC;EAAU,SAAS,OAAT;;AACX,4BAAC;EAAU,SAAS,OAAT;;AACX,6BAAC;EAAU,SAAS,OAAT;;AACX,iCAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,wBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,eAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,wBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,kBAAC;EAAU,SAAS,OAAT;;AACX,iBAAC;EAAU,SAAS,OAAT;;AACX,qBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,gBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,mBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,sBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,oBAAC;EAAU,SAAS,OAAT;;AACX,yBAAC;EAAU,SAAS,OAAT;;AACX,4BAAC;EAAU,SAAS,OAAT;;AACX,yBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,uBAAC;EAAU,SAAS,OAAT;;AACX,yBAAC;EAAU,SAAS,OAAT;;AClO/C;EACE,qBAAA;EACA,QAAA;EACA,SAAA;EACA,gBAAA;EACA,sBAAA;EACA,qBAAA;EACA,mCAAA;EACA,kCAAA;;AAIF;EACE,kBAAA;;AAIF,gBAAgB;EACd,UAAA;;AAIF;EACE,kBAAA;EACA,SAAA;EACA,OAAA;EACA,aAAA;EACA,aAAA;EACA,WAAA;EACA,gBAAA;EACA,cAAA;EACA,eAAA;EACA,gBAAA;EACA,eAAA;EACA,yBAAA;EACA,yBAAA;EACA,qCAAA;EACA,kBAAA;Eb8EA,mDAAA;EACQ,2CAAA;Ea7ER,4BAAA;;AAKA,cAAC;EACC,QAAA;EACA,UAAA;;AAxBJ,cA4BE;EboVA,WAAA;EACA,aAAA;EACA,gBAAA;EACA,yBAAA;;AanXF,cAiCE,KAAK;EACH,cAAA;EACA,iBAAA;EACA,WAAA;EACA,mBAAA;EACA,uBAAA;EACA,cAAA;EACA,mBAAA;;AAMF,cADa,KAAK,IACjB;AACD,cAFa,KAAK,IAEjB;EACC,qBAAA;EACA,cAAA;EACA,yBAAA;;AAMF,cADa,UAAU;AAEvB,cAFa,UAAU,IAEtB;AACD,cAHa,UAAU,IAGtB;EACC,cAAA;EACA,qBAAA;EACA,UAAA;EACA,yBAAA;;AASF,cADa,YAAY;AAEzB,cAFa,YAAY,IAExB;AACD,cAHa,YAAY,IAGxB;EACC,cAAA;;AAKF,cADa,YAAY,IACxB;AACD,cAFa,YAAY,IAExB;EACC,qBAAA;EACA,6BAAA;EACA,sBAAA;EbkPF,mEAAA;EahPE,mBAAA;;AAKJ,KAEE;EACE,cAAA;;AAHJ,KAOE;EACE,UAAA;;AAQJ;EACE,UAAA;EACA,QAAA;;AAQF;EACE,OAAA;EACA,WAAA;;AAIF;EACE,cAAA;EACA,iBAAA;EACA,eAAA;EACA,uBAAA;EACA,cAAA;;AAIF;EACE,eAAA;EACA,OAAA;EACA,QAAA;EACA,SAAA;EACA,MAAA;EACA,YAAA;;AAIF,WAAY;EACV,QAAA;EACA,UAAA;;AAQF,OAGE;AAFF,oBAAqB,UAEnB;EACE,aAAA;EACA,wBAAA;EACA,SAAS,EAAT;;AANJ,OASE;AARF,oBAAqB,UAQnB;EACE,SAAA;EACA,YAAA;EACA,kBAAA;;AAsBJ,QAb2C;EACzC,aACE;IAnEF,UAAA;IACA,QAAA;;EAiEA,aAME;IA9DF,OAAA;IACA,WAAA;;;AH7IF;AACA;EACE,kBAAA;EACA,qBAAA;EACA,sBAAA;;AAJF,UAKE;AAJF,mBAIE;EACE,kBAAA;EACA,WAAA;;AAEA,UAJF,OAIG;AAAD,mBAJF,OAIG;AACD,UALF,OAKG;AAAD,mBALF,OAKG;AACD,UANF,OAMG;AAAD,mBANF,OAMG;AACD,UAPF,OAOG;AAAD,mBAPF,OAOG;EACC,UAAA;;AAEF,UAVF,OAUG;AAAD,mBAVF,OAUG;EAEC,aAAA;;AAMN,UACE,KAAK;AADP,UAEE,KAAK;AAFP,UAGE,WAAW;AAHb,UAIE,WAAW;EACT,iBAAA;;AAKJ;EACE,iBAAA;;AADF,YAIE;AAJF,YAKE;EACE,WAAA;;AANJ,YAQE;AARF,YASE;AATF,YAUE;EACE,gBAAA;;AAIJ,UAAW,OAAM,IAAI,cAAc,IAAI,aAAa,IAAI;EACtD,gBAAA;;AAIF,UAAW,OAAM;EACf,cAAA;;AACA,UAFS,OAAM,YAEd,IAAI,aAAa,IAAI;EV2CtB,6BAAA;EACG,0BAAA;;AUvCL,UAAW,OAAM,WAAW,IAAI;AAChC,UAAW,mBAAkB,IAAI;EV6C/B,4BAAA;EACG,yBAAA;;AUzCL,UAAW;EACT,WAAA;;AAEF,UAAW,aAAY,IAAI,cAAc,IAAI,aAAc;EACzD,gBAAA;;AAEF,UAAW,aAAY,YACrB,OAAM;AADR,UAAW,aAAY,YAErB;EVwBA,6BAAA;EACG,0BAAA;;AUrBL,UAAW,aAAY,WAAY,OAAM;EV4BvC,4BAAA;EACG,yBAAA;;AUxBL,UAAW,iBAAgB;AAC3B,UAAU,KAAM;EACd,UAAA;;AAiBF,UAAW,OAAO;EAChB,iBAAA;EACA,kBAAA;;AAEF,UAAW,UAAU;EACnB,kBAAA;EACA,mBAAA;;AAKF,UAAU,KAAM;EVGd,wDAAA;EACQ,gDAAA;;AUAR,UAJQ,KAAM,iBAIb;EVDD,wBAAA;EACQ,gBAAA;;AUOV,IAAK;EACH,cAAA;;AAGF,OAAQ;EACN,uBAAA;EACA,sBAAA;;AAGF,OAAQ,QAAQ;EACd,uBAAA;;AAOF,mBACE;AADF,mBAEE;AAFF,mBAGE,aAAa;EACX,cAAA;EACA,WAAA;EACA,WAAA;EACA,eAAA;;AAPJ,mBAWE,aAEE;EACE,WAAA;;AAdN,mBAkBE,OAAO;AAlBT,mBAmBE,OAAO;AAnBT,mBAoBE,aAAa;AApBf,mBAqBE,aAAa;EACX,gBAAA;EACA,cAAA;;AAKF,mBADkB,OACjB,IAAI,cAAc,IAAI;EACrB,gBAAA;;AAEF,mBAJkB,OAIjB,YAAY,IAAI;EACf,4BAAA;EVvEF,6BAAA;EACC,4BAAA;;AUyED,mBARkB,OAQjB,WAAW,IAAI;EACd,8BAAA;EVnFF,0BAAA;EACC,yBAAA;;AUsFH,mBAAoB,aAAY,IAAI,cAAc,IAAI,aAAc;EAClE,gBAAA;;AAEF,mBAAoB,aAAY,YAAY,IAAI,aAC9C,OAAM;AADR,mBAAoB,aAAY,YAAY,IAAI,aAE9C;EVpFA,6BAAA;EACC,4BAAA;;AUuFH,mBAAoB,aAAY,WAAW,IAAI,cAAe,OAAM;EVhGlE,0BAAA;EACC,yBAAA;;AUwGH;EACE,cAAA;EACA,WAAA;EACA,mBAAA;EACA,yBAAA;;AAJF,oBAKE;AALF,oBAME;EACE,WAAA;EACA,mBAAA;EACA,SAAA;;AATJ,oBAWE,aAAa;EACX,WAAA;;AAMJ,uBAAwB,OAAO,QAAO;AACtC,uBAAwB,OAAO,QAAO;EACpC,aAAA;;AI1NF;EACE,kBAAA;EACA,cAAA;EACA,yBAAA;;AAGA,YAAC;EACC,WAAA;EACA,eAAA;EACA,gBAAA;;AATJ,YAYE;EAGE,kBAAA;EACA,UAAA;EAKA,WAAA;EAEA,WAAA;EACA,gBAAA;;AASJ,eAAgB;AAChB,eAAgB;AAChB,eAAgB,mBAAmB;Edw2BjC,YAAA;EACA,kBAAA;EACA,eAAA;EACA,iBAAA;EACA,kBAAA;;AAEA,MAAM,ech3BQ;Adg3Bd,MAAM,ec/2BQ;Ad+2Bd,MAAM,ec92BQ,mBAAmB;Ed+2B/B,YAAA;EACA,iBAAA;;AAGF,QAAQ,ecr3BM;Adq3Bd,QAAQ,ecp3BM;Ado3Bd,QAAQ,ecn3BM,mBAAmB;Ado3BjC,MAAM,UAAU,ect3BF;Ads3Bd,MAAM,UAAU,ecr3BF;Adq3Bd,MAAM,UAAU,ecp3BF,mBAAmB;Edq3B/B,YAAA;;Acp3BJ,eAAgB;AAChB,eAAgB;AAChB,eAAgB,mBAAmB;Edq2BjC,YAAA;EACA,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,kBAAA;;AAEA,MAAM,ec72BQ;Ad62Bd,MAAM,ec52BQ;Ad42Bd,MAAM,ec32BQ,mBAAmB;Ed42B/B,YAAA;EACA,iBAAA;;AAGF,QAAQ,ecl3BM;Adk3Bd,QAAQ,ecj3BM;Adi3Bd,QAAQ,ech3BM,mBAAmB;Adi3BjC,MAAM,UAAU,ecn3BF;Adm3Bd,MAAM,UAAU,ecl3BF;Adk3Bd,MAAM,UAAU,ecj3BF,mBAAmB;Edk3B/B,YAAA;;Ac72BJ;AACA;AACA,YAAa;EACX,mBAAA;;AAEA,kBAAC,IAAI,cAAc,IAAI;AAAvB,gBAAC,IAAI,cAAc,IAAI;AAAvB,YAHW,cAGV,IAAI,cAAc,IAAI;EACrB,gBAAA;;AAIJ;AACA;EACE,SAAA;EACA,mBAAA;EACA,sBAAA;;AAKF;EACE,iBAAA;EACA,eAAA;EACA,mBAAA;EACA,cAAA;EACA,cAAA;EACA,kBAAA;EACA,yBAAA;EACA,yBAAA;EACA,kBAAA;;AAGA,kBAAC;EACC,iBAAA;EACA,eAAA;EACA,kBAAA;;AAEF,kBAAC;EACC,kBAAA;EACA,eAAA;EACA,kBAAA;;AApBJ,kBAwBE,MAAK;AAxBP,kBAyBE,MAAK;EACH,aAAA;;AAKJ,YAAa,cAAa;AAC1B,kBAAkB;AAClB,gBAAgB,YAAa;AAC7B,gBAAgB,YAAa,aAAa;AAC1C,gBAAgB,YAAa;AAC7B,gBAAgB,WAAY,OAAM,IAAI,aAAa,IAAI;AACvD,gBAAgB,WAAY,aAAY,IAAI,aAAc;EdFxD,6BAAA;EACG,0BAAA;;AcIL,kBAAkB;EAChB,eAAA;;AAEF,YAAa,cAAa;AAC1B,kBAAkB;AAClB,gBAAgB,WAAY;AAC5B,gBAAgB,WAAY,aAAa;AACzC,gBAAgB,WAAY;AAC5B,gBAAgB,YAAa,OAAM,IAAI;AACvC,gBAAgB,YAAa,aAAY,IAAI,cAAe;EdN1D,4BAAA;EACG,yBAAA;;AcQL,kBAAkB;EAChB,cAAA;;AAKF;EACE,kBAAA;EAGA,YAAA;EACA,mBAAA;;AALF,gBASE;EACE,kBAAA;;AAVJ,gBASE,OAEE;EACE,iBAAA;;AAGF,gBANF,OAMG;AACD,gBAPF,OAOG;AACD,gBARF,OAQG;EACC,UAAA;;AAKJ,gBAAC,YACC;AADF,gBAAC,YAEC;EACE,kBAAA;;AAGJ,gBAAC,WACC;AADF,gBAAC,WAEC;EACE,iBAAA;;ACtJN;EACE,gBAAA;EACA,eAAA;EACA,gBAAA;;AAHF,IAME;EACE,kBAAA;EACA,cAAA;;AARJ,IAME,KAIE;EACE,kBAAA;EACA,cAAA;EACA,kBAAA;;AACA,IARJ,KAIE,IAIG;AACD,IATJ,KAIE,IAKG;EACC,qBAAA;EACA,yBAAA;;AAKJ,IAhBF,KAgBG,SAAU;EACT,cAAA;;AAEA,IAnBJ,KAgBG,SAAU,IAGR;AACD,IApBJ,KAgBG,SAAU,IAIR;EACC,cAAA;EACA,qBAAA;EACA,6BAAA;EACA,mBAAA;;AAOJ,IADF,MAAM;AAEJ,IAFF,MAAM,IAEH;AACD,IAHF,MAAM,IAGH;EACC,yBAAA;EACA,qBAAA;;AAzCN,IAkDE;EfkVA,WAAA;EACA,aAAA;EACA,gBAAA;EACA,yBAAA;;AevYF,IAyDE,KAAK,IAAI;EACP,eAAA;;AASJ;EACE,gCAAA;;AADF,SAEE;EACE,WAAA;EAEA,mBAAA;;AALJ,SAEE,KAME;EACE,iBAAA;EACA,uBAAA;EACA,6BAAA;EACA,0BAAA;;AACA,SAXJ,KAME,IAKG;EACC,qCAAA;;AAMF,SAlBJ,KAiBG,OAAQ;AAEP,SAnBJ,KAiBG,OAAQ,IAEN;AACD,SApBJ,KAiBG,OAAQ,IAGN;EACC,cAAA;EACA,yBAAA;EACA,yBAAA;EACA,gCAAA;EACA,eAAA;;AAKN,SAAC;EAqDD,WAAA;EA8BA,gBAAA;;AAnFA,SAAC,cAuDD;EACE,WAAA;;AAxDF,SAAC,cAuDD,KAEG;EACC,kBAAA;EACA,kBAAA;;AA3DJ,SAAC,cA+DD,YAAY;EACV,SAAA;EACA,UAAA;;AAYJ,QATqC;EASrC,SA7EG,cAqEC;IACE,mBAAA;IACA,SAAA;;EAMN,SA7EG,cAqEC,KAGE;IACE,gBAAA;;;AAzEN,SAAC,cAqFD,KAAK;EAEH,eAAA;EACA,kBAAA;;AAxFF,SAAC,cA2FD,UAAU;AA3FV,SAAC,cA4FD,UAAU,IAAG;AA5Fb,SAAC,cA6FD,UAAU,IAAG;EACX,yBAAA;;AAcJ,QAXqC;EAWrC,SA5GG,cAkGC,KAAK;IACH,gCAAA;IACA,0BAAA;;EAQN,SA5GG,cAsGC,UAAU;EAMd,SA5GG,cAuGC,UAAU,IAAG;EAKjB,SA5GG,cAwGC,UAAU,IAAG;IACX,4BAAA;;;AAhGN,UACE;EACE,WAAA;;AAFJ,UACE,KAIE;EACE,kBAAA;;AANN,UACE,KAOE;EACE,gBAAA;;AAKA,UAbJ,KAYG,OAAQ;AAEP,UAdJ,KAYG,OAAQ,IAEN;AACD,UAfJ,KAYG,OAAQ,IAGN;EACC,cAAA;EACA,yBAAA;;AAQR,YACE;EACE,WAAA;;AAFJ,YACE,KAEE;EACE,eAAA;EACA,cAAA;;AAYN;EACE,WAAA;;AADF,cAGE;EACE,WAAA;;AAJJ,cAGE,KAEG;EACC,kBAAA;EACA,kBAAA;;AAPN,cAWE,YAAY;EACV,SAAA;EACA,UAAA;;AAYJ,QATqC;EASrC,cARI;IACE,mBAAA;IACA,SAAA;;EAMN,cARI,KAGE;IACE,gBAAA;;;AASR;EACE,gBAAA;;AADF,mBAGE,KAAK;EAEH,eAAA;EACA,kBAAA;;AANJ,mBASE,UAAU;AATZ,mBAUE,UAAU,IAAG;AAVf,mBAWE,UAAU,IAAG;EACX,yBAAA;;AAcJ,QAXqC;EAWrC,mBAVI,KAAK;IACH,gCAAA;IACA,0BAAA;;EAQN,mBANI,UAAU;EAMd,mBALI,UAAU,IAAG;EAKjB,mBAJI,UAAU,IAAG;IACX,4BAAA;;;AAUN,YACE;EACE,aAAA;;AAFJ,YAIE;EACE,cAAA;;AASJ,SAAU;EAER,gBAAA;Ef3IA,0BAAA;EACC,yBAAA;;AgB1FH;EACE,kBAAA;EACA,gBAAA;EACA,mBAAA;EACA,6BAAA;;AAQF,QAH6C;EAG7C;IAFI,kBAAA;;;AAgBJ,QAH6C;EAG7C;IAFI,WAAA;;;AAeJ;EACE,iBAAA;EACA,mBAAA;EACA,mBAAA;EACA,kBAAA;EACA,iCAAA;EACA,kDAAA;EAEA,iCAAA;;AAEA,gBAAC;EACC,gBAAA;;AA4BJ,QAzB6C;EAyB7C;IAxBI,WAAA;IACA,aAAA;IACA,gBAAA;;EAEA,gBAAC;IACC,yBAAA;IACA,uBAAA;IACA,iBAAA;IACA,4BAAA;;EAGF,gBAAC;IACC,mBAAA;;EAKF,iBAAkB;EAClB,kBAAmB;EACnB,oBAAqB;IACnB,eAAA;IACA,gBAAA;;;AAUN,UAEE;AADF,gBACE;AAFF,UAGE;AAFF,gBAEE;EACE,mBAAA;EACA,kBAAA;;AAMF,QAJ6C;EAI7C,UATA;EASA,gBATA;EASA,UARA;EAQA,gBARA;IAKI,eAAA;IACA,cAAA;;;AAaN;EACE,aAAA;EACA,qBAAA;;AAKF,QAH6C;EAG7C;IAFI,gBAAA;;;AAKJ;AACA;EACE,eAAA;EACA,QAAA;EACA,OAAA;EACA,aAAA;;AAMF,QAH6C;EAG7C;EAAA;IAFI,gBAAA;;;AAGJ;EACE,MAAA;EACA,qBAAA;;AAEF;EACE,SAAA;EACA,gBAAA;EACA,qBAAA;;AAMF;EACE,WAAA;EACA,kBAAA;EACA,eAAA;EACA,iBAAA;EACA,YAAA;;AAEA,aAAC;AACD,aAAC;EACC,qBAAA;;AASJ,QAN6C;EACzC,OAAQ,aAAa;EACrB,OAAQ,mBAAmB;IACzB,kBAAA;;;AAWN;EACE,kBAAA;EACA,YAAA;EACA,kBAAA;EACA,iBAAA;EhBsaA,eAAA;EACA,kBAAA;EgBraA,6BAAA;EACA,sBAAA;EACA,6BAAA;EACA,kBAAA;;AAIA,cAAC;EACC,aAAA;;AAdJ,cAkBE;EACE,cAAA;EACA,WAAA;EACA,WAAA;EACA,kBAAA;;AAtBJ,cAwBE,UAAU;EACR,eAAA;;AAMJ,QAH6C;EAG7C;IAFI,aAAA;;;AAUJ;EACE,mBAAA;;AADF,WAGE,KAAK;EACH,iBAAA;EACA,oBAAA;EACA,iBAAA;;AA2BF,QAxB+C;EAwB/C,WAtBE,MAAM;IACJ,gBAAA;IACA,WAAA;IACA,WAAA;IACA,aAAA;IACA,6BAAA;IACA,SAAA;IACA,gBAAA;;EAeJ,WAtBE,MAAM,eAQJ,KAAK;EAcT,WAtBE,MAAM,eASJ;IACE,0BAAA;;EAYN,WAtBE,MAAM,eAYJ,KAAK;IACH,iBAAA;;EACA,WAdJ,MAAM,eAYJ,KAAK,IAEF;EACD,WAfJ,MAAM,eAYJ,KAAK,IAGF;IACC,sBAAA;;;AAuBV,QAhB6C;EAgB7C;IAfI,WAAA;IACA,SAAA;;EAcJ,WAZI;IACE,WAAA;;EAWN,WAZI,KAEE;IACE,iBAAA;IACA,oBAAA;;EAIJ,WAAC,aAAa;IACZ,mBAAA;;;AAkBN,QAN2C;EACzC;ICnQA,sBAAA;;EDoQA;ICvQA,uBAAA;;;ADgRF;EACE,kBAAA;EACA,mBAAA;EACA,kBAAA;EACA,iCAAA;EACA,oCAAA;EhB3KA,4FAAA;EACQ,oFAAA;EAkeR,eAAA;EACA,kBAAA;;AQ3NF,QAjDqC;EAiDrC,YA/CI;IACE,qBAAA;IACA,gBAAA;IACA,sBAAA;;EA4CN,YAxCI;IACE,qBAAA;IACA,WAAA;IACA,sBAAA;;EAqCN,YAlCI,aAAa;IACX,WAAA;;EAiCN,YA9BI;IACE,gBAAA;IACA,sBAAA;;EA4BN,YAtBI;EAsBJ,YArBI;IACE,qBAAA;IACA,aAAA;IACA,gBAAA;IACA,eAAA;IACA,sBAAA;;EAgBN,YAdI,OAAO,MAAK;EAchB,YAbI,UAAU,MAAK;IACb,WAAA;IACA,cAAA;;EAWN,YAJI,cAAc;IACZ,MAAA;;;AQhFJ,QAHiD;EAGjD,YAJA;IAEI,kBAAA;;;AAsBN,QAd6C;EAc7C;IAbI,WAAA;IACA,SAAA;IACA,cAAA;IACA,eAAA;IACA,cAAA;IACA,iBAAA;IhBlMF,wBAAA;IACQ,gBAAA;;EgBqMN,YAAC,aAAa;IACZ,mBAAA;;;AASN,WAAY,KAAK;EACf,aAAA;EhBvOA,0BAAA;EACC,yBAAA;;AgB0OH,oBAAqB,YAAY,KAAK;EhBnOpC,6BAAA;EACC,4BAAA;;AgB2OH;EhBqQE,eAAA;EACA,kBAAA;;AgBnQA,WAAC;EhBkQD,gBAAA;EACA,mBAAA;;AgBhQA,WAAC;EhB+PD,gBAAA;EACA,mBAAA;;AgBtPF;EhBqPE,gBAAA;EACA,mBAAA;;AgBzOF,QAV6C;EAU7C;IATI,WAAA;IACA,iBAAA;IACA,kBAAA;;EAGA,YAAC,aAAa;IACZ,eAAA;;;AASN;EACE,yBAAA;EACA,qBAAA;;AAFF,eAIE;EACE,cAAA;;AACA,eAFF,cAEG;AACD,eAHF,cAGG;EACC,cAAA;EACA,6BAAA;;AATN,eAaE;EACE,cAAA;;AAdJ,eAiBE,YACE,KAAK;EACH,cAAA;;AAEA,eAJJ,YACE,KAAK,IAGF;AACD,eALJ,YACE,KAAK,IAIF;EACC,cAAA;EACA,6BAAA;;AAIF,eAXJ,YAUE,UAAU;AAER,eAZJ,YAUE,UAAU,IAEP;AACD,eAbJ,YAUE,UAAU,IAGP;EACC,cAAA;EACA,yBAAA;;AAIF,eAnBJ,YAkBE,YAAY;AAEV,eApBJ,YAkBE,YAAY,IAET;AACD,eArBJ,YAkBE,YAAY,IAGT;EACC,cAAA;EACA,6BAAA;;AAxCR,eA6CE;EACE,qBAAA;;AACA,eAFF,eAEG;AACD,eAHF,eAGG;EACC,yBAAA;;AAjDN,eA6CE,eAME;EACE,yBAAA;;AApDN,eAwDE;AAxDF,eAyDE;EACE,qBAAA;;AAOE,eAHJ,YAEE,QAAQ;AAEN,eAJJ,YAEE,QAAQ,IAEL;AACD,eALJ,YAEE,QAAQ,IAGL;EACC,yBAAA;EACA,cAAA;;AAiCN,QA7BiD;EA6BjD,eAxCA,YAaI,MAAM,eACJ,KAAK;IACH,cAAA;;EACA,eAhBR,YAaI,MAAM,eACJ,KAAK,IAEF;EACD,eAjBR,YAaI,MAAM,eACJ,KAAK,IAGF;IACC,cAAA;IACA,6BAAA;;EAIF,eAvBR,YAaI,MAAM,eASJ,UAAU;EAER,eAxBR,YAaI,MAAM,eASJ,UAAU,IAEP;EACD,eAzBR,YAaI,MAAM,eASJ,UAAU,IAGP;IACC,cAAA;IACA,yBAAA;;EAIF,eA/BR,YAaI,MAAM,eAiBJ,YAAY;EAEV,eAhCR,YAaI,MAAM,eAiBJ,YAAY,IAET;EACD,eAjCR,YAaI,MAAM,eAiBJ,YAAY,IAGT;IACC,cAAA;IACA,6BAAA;;;AAjGZ,eA6GE;EACE,cAAA;;AACA,eAFF,aAEG;EACC,cAAA;;AAQN;EACE,yBAAA;EACA,qBAAA;;AAFF,eAIE;EACE,cAAA;;AACA,eAFF,cAEG;AACD,eAHF,cAGG;EACC,cAAA;EACA,6BAAA;;AATN,eAaE;EACE,cAAA;;AAdJ,eAiBE,YACE,KAAK;EACH,cAAA;;AAEA,eAJJ,YACE,KAAK,IAGF;AACD,eALJ,YACE,KAAK,IAIF;EACC,cAAA;EACA,6BAAA;;AAIF,eAXJ,YAUE,UAAU;AAER,eAZJ,YAUE,UAAU,IAEP;AACD,eAbJ,YAUE,UAAU,IAGP;EACC,cAAA;EACA,yBAAA;;AAIF,eAnBJ,YAkBE,YAAY;AAEV,eApBJ,YAkBE,YAAY,IAET;AACD,eArBJ,YAkBE,YAAY,IAGT;EACC,cAAA;EACA,6BAAA;;AAxCR,eA8CE;EACE,qBAAA;;AACA,eAFF,eAEG;AACD,eAHF,eAGG;EACC,yBAAA;;AAlDN,eA8CE,eAME;EACE,yBAAA;;AArDN,eAyDE;AAzDF,eA0DE;EACE,qBAAA;;AAME,eAFJ,YACE,QAAQ;AAEN,eAHJ,YACE,QAAQ,IAEL;AACD,eAJJ,YACE,QAAQ,IAGL;EACC,yBAAA;EACA,cAAA;;AAuCN,QAnCiD;EAmCjD,eA7CA,YAYI,MAAM,eACJ;IACE,qBAAA;;EA+BR,eA7CA,YAYI,MAAM,eAIJ;IACE,yBAAA;;EA4BR,eA7CA,YAYI,MAAM,eAOJ,KAAK;IACH,cAAA;;EACA,eArBR,YAYI,MAAM,eAOJ,KAAK,IAEF;EACD,eAtBR,YAYI,MAAM,eAOJ,KAAK,IAGF;IACC,cAAA;IACA,6BAAA;;EAIF,eA5BR,YAYI,MAAM,eAeJ,UAAU;EAER,eA7BR,YAYI,MAAM,eAeJ,UAAU,IAEP;EACD,eA9BR,YAYI,MAAM,eAeJ,UAAU,IAGP;IACC,cAAA;IACA,yBAAA;;EAIF,eApCR,YAYI,MAAM,eAuBJ,YAAY;EAEV,eArCR,YAYI,MAAM,eAuBJ,YAAY,IAET;EACD,eAtCR,YAYI,MAAM,eAuBJ,YAAY,IAGT;IACC,cAAA;IACA,6BAAA;;;AAvGZ,eA8GE;EACE,cAAA;;AACA,eAFF,aAEG;EACC,cAAA;;AE9lBN;EACE,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,yBAAA;EACA,kBAAA;;AALF,WAOE;EACE,qBAAA;;AARJ,WAOE,KAGE,KAAI;EACF,SAAS,QAAT;EACA,cAAA;EACA,cAAA;;AAbN,WAiBE;EACE,cAAA;;ACpBJ;EACE,qBAAA;EACA,eAAA;EACA,cAAA;EACA,kBAAA;;AAJF,WAME;EACE,eAAA;;AAPJ,WAME,KAEE;AARJ,WAME,KAGE;EACE,kBAAA;EACA,WAAA;EACA,iBAAA;EACA,uBAAA;EACA,qBAAA;EACA,cAAA;EACA,yBAAA;EACA,yBAAA;EACA,iBAAA;;AAEF,WAdF,KAcG,YACC;AADF,WAdF,KAcG,YAEC;EACE,cAAA;EnBqFN,8BAAA;EACG,2BAAA;;AmBlFD,WArBF,KAqBG,WACC;AADF,WArBF,KAqBG,WAEC;EnBuEJ,+BAAA;EACG,4BAAA;;AmBhED,WAFF,KAAK,IAEF;AAAD,WADF,KAAK,OACF;AACD,WAHF,KAAK,IAGF;AAAD,WAFF,KAAK,OAEF;EACC,cAAA;EACA,yBAAA;EACA,qBAAA;;AAMF,WAFF,UAAU;AAER,WADF,UAAU;AAER,WAHF,UAAU,IAGP;AAAD,WAFF,UAAU,OAEP;AACD,WAJF,UAAU,IAIP;AAAD,WAHF,UAAU,OAGP;EACC,UAAA;EACA,cAAA;EACA,yBAAA;EACA,qBAAA;EACA,eAAA;;AAtDN,WA0DE,YACE;AA3DJ,WA0DE,YAEE,OAAM;AA5DV,WA0DE,YAGE,OAAM;AA7DV,WA0DE,YAIE;AA9DJ,WA0DE,YAKE,IAAG;AA/DP,WA0DE,YAME,IAAG;EACD,cAAA;EACA,yBAAA;EACA,qBAAA;EACA,mBAAA;;AASN,cnBodE,KACE;AmBrdJ,cnBodE,KAEE;EACE,kBAAA;EACA,eAAA;;AAEF,cANF,KAMG,YACC;AADF,cANF,KAMG,YAEC;EA7bJ,8BAAA;EACG,2BAAA;;AAgcD,cAZF,KAYG,WACC;AADF,cAZF,KAYG,WAEC;EA3cJ,+BAAA;EACG,4BAAA;;AmBnBL,cnB+cE,KACE;AmBhdJ,cnB+cE,KAEE;EACE,iBAAA;EACA,eAAA;;AAEF,cANF,KAMG,YACC;AADF,cANF,KAMG,YAEC;EA7bJ,8BAAA;EACG,2BAAA;;AAgcD,cAZF,KAYG,WACC;AADF,cAZF,KAYG,WAEC;EA3cJ,+BAAA;EACG,4BAAA;;AoBnGL;EACE,eAAA;EACA,cAAA;EACA,gBAAA;EACA,kBAAA;;AAJF,MAME;EACE,eAAA;;AAPJ,MAME,GAEE;AARJ,MAME,GAGE;EACE,qBAAA;EACA,iBAAA;EACA,yBAAA;EACA,yBAAA;EACA,mBAAA;;AAdN,MAME,GAWE,IAAG;AAjBP,MAME,GAYE,IAAG;EACD,qBAAA;EACA,yBAAA;;AApBN,MAwBE,MACE;AAzBJ,MAwBE,MAEE;EACE,YAAA;;AA3BN,MA+BE,UACE;AAhCJ,MA+BE,UAEE;EACE,WAAA;;AAlCN,MAsCE,UACE;AAvCJ,MAsCE,UAEE,IAAG;AAxCP,MAsCE,UAGE,IAAG;AAzCP,MAsCE,UAIE;EACE,cAAA;EACA,yBAAA;EACA,mBAAA;;AC9CN;EACE,eAAA;EACA,uBAAA;EACA,cAAA;EACA,iBAAA;EACA,cAAA;EACA,cAAA;EACA,kBAAA;EACA,mBAAA;EACA,wBAAA;EACA,oBAAA;;AAIE,MADD,MACE;AACD,MAFD,MAEE;EACC,cAAA;EACA,qBAAA;EACA,eAAA;;AAKJ,MAAC;EACC,aAAA;;AAIF,IAAK;EACH,kBAAA;EACA,SAAA;;AAOJ;ErBmhBE,yBAAA;;AAEE,cADD,MACE;AACD,cAFD,MAEE;EACC,yBAAA;;AqBnhBN;ErB+gBE,yBAAA;;AAEE,cADD,MACE;AACD,cAFD,MAEE;EACC,yBAAA;;AqB/gBN;ErB2gBE,yBAAA;;AAEE,cADD,MACE;AACD,cAFD,MAEE;EACC,yBAAA;;AqB3gBN;ErBugBE,yBAAA;;AAEE,WADD,MACE;AACD,WAFD,MAEE;EACC,yBAAA;;AqBvgBN;ErBmgBE,yBAAA;;AAEE,cADD,MACE;AACD,cAFD,MAEE;EACC,yBAAA;;AqBngBN;ErB+fE,yBAAA;;AAEE,aADD,MACE;AACD,aAFD,MAEE;EACC,yBAAA;;AsB1jBN;EACE,qBAAA;EACA,eAAA;EACA,gBAAA;EACA,eAAA;EACA,iBAAA;EACA,cAAA;EACA,cAAA;EACA,wBAAA;EACA,mBAAA;EACA,kBAAA;EACA,yBAAA;EACA,mBAAA;;AAGA,MAAC;EACC,aAAA;;AAIF,IAAK;EACH,kBAAA;EACA,SAAA;;AAEF,OAAQ;EACN,MAAA;EACA,gBAAA;;AAMF,CADD,MACE;AACD,CAFD,MAEE;EACC,cAAA;EACA,qBAAA;EACA,eAAA;;AAKJ,CAAC,gBAAgB,OAAQ;AACzB,UAAW,UAAU,IAAI;EACvB,cAAA;EACA,yBAAA;;AAEF,UAAW,KAAK,IAAI;EAClB,gBAAA;;AChDF;EACE,aAAA;EACA,mBAAA;EACA,cAAA;EACA,yBAAA;;AAJF,UAME;AANF,UAOE;EACE,cAAA;;AARJ,UAUE;EACE,mBAAA;EACA,eAAA;EACA,gBAAA;;AAGF,UAAW;EACT,kBAAA;;AAjBJ,UAoBE;EACE,eAAA;;AAiBJ,mBAdgD;EAchD;IAbI,iBAAA;IACA,oBAAA;;EAEA,UAAW;IACT,kBAAA;IACA,mBAAA;;EAQN,UALI;EAKJ,UAJI;IACE,eAAA;;;ArBlCN;EACE,cAAA;EACA,YAAA;EACA,mBAAA;EACA,uBAAA;EACA,yBAAA;EACA,yBAAA;EACA,kBAAA;EFkHA,wCAAA;EACQ,gCAAA;;AE1HV,UAUE;AAVF,UAWE,EAAE;EAEA,iBAAA;EACA,kBAAA;;AAIF,CAAC,UAAC;AACF,CAAC,UAAC;AACF,CAAC,UAAC;EACA,qBAAA;;AArBJ,UAyBE;EACE,YAAA;EACA,cAAA;;AsBzBJ;EACE,aAAA;EACA,mBAAA;EACA,6BAAA;EACA,kBAAA;;AAJF,MAOE;EACE,aAAA;EAEA,cAAA;;AAVJ,MAaE;EACE,iBAAA;;AAdJ,MAkBE;AAlBF,MAmBE;EACE,gBAAA;;AApBJ,MAsBE,IAAI;EACF,eAAA;;AAQJ;EACC,mBAAA;;AADD,kBAIE;EACE,kBAAA;EACA,SAAA;EACA,YAAA;EACA,cAAA;;AAQJ;ExBmXE,yBAAA;EACA,qBAAA;EACA,cAAA;;AwBrXF,cxBuXE;EACE,yBAAA;;AwBxXJ,cxB0XE;EACE,cAAA;;AwBxXJ;ExBgXE,yBAAA;EACA,qBAAA;EACA,cAAA;;AwBlXF,WxBoXE;EACE,yBAAA;;AwBrXJ,WxBuXE;EACE,cAAA;;AwBrXJ;ExB6WE,yBAAA;EACA,qBAAA;EACA,cAAA;;AwB/WF,cxBiXE;EACE,yBAAA;;AwBlXJ,cxBoXE;EACE,cAAA;;AwBlXJ;ExB0WE,yBAAA;EACA,qBAAA;EACA,cAAA;;AwB5WF,axB8WE;EACE,yBAAA;;AwB/WJ,axBiXE;EACE,cAAA;;AyBzaJ;EACE;IAAQ,2BAAA;;EACR;IAAQ,wBAAA;;;AAIV;EACE;IAAQ,2BAAA;;EACR;IAAQ,wBAAA;;;AASV;EACE,gBAAA;EACA,YAAA;EACA,mBAAA;EACA,yBAAA;EACA,kBAAA;EzB0FA,sDAAA;EACQ,8CAAA;;AyBtFV;EACE,WAAA;EACA,SAAA;EACA,YAAA;EACA,eAAA;EACA,iBAAA;EACA,cAAA;EACA,kBAAA;EACA,yBAAA;EzB6EA,sDAAA;EACQ,8CAAA;EAKR,mCAAA;EACQ,2BAAA;;AyB9EV,iBAAkB;EzBqSd,kBAAkB,2LAAlB;EACA,kBAAkB,mLAAlB;EyBpSF,0BAAA;;AAIF,SAAS,OAAQ;EzBoJf,0DAAA;EACQ,kDAAA;;AyB5IV;EzBkiBE,yBAAA;;AACA,iBAAkB;EA7QhB,kBAAkB,2LAAlB;EACA,kBAAkB,mLAAlB;;AyBnRJ;EzB8hBE,yBAAA;;AACA,iBAAkB;EA7QhB,kBAAkB,2LAAlB;EACA,kBAAkB,mLAAlB;;AyB/QJ;EzB0hBE,yBAAA;;AACA,iBAAkB;EA7QhB,kBAAkB,2LAAlB;EACA,kBAAkB,mLAAlB;;AyB3QJ;EzBshBE,yBAAA;;AACA,iBAAkB;EA7QhB,kBAAkB,2LAAlB;EACA,kBAAkB,mLAAlB;;A0B/UJ;AACA;EACE,gBAAA;EACA,OAAA;;AAIF;AACA,MAAO;EACL,gBAAA;;AAEF,MAAM;EACJ,aAAA;;AAIF;EACE,cAAA;;AAIF;EACE,eAAA;;AAOF,MACE;EACE,kBAAA;;AAFJ,MAIE;EACE,iBAAA;;AASJ;EACE,eAAA;EACA,gBAAA;;AC7CF;EAEE,mBAAA;EACA,eAAA;;AAQF;EACE,kBAAA;EACA,cAAA;EACA,kBAAA;EAEA,mBAAA;EACA,yBAAA;EACA,yBAAA;;AAGA,gBAAC;E3BqED,4BAAA;EACC,2BAAA;;A2BnED,gBAAC;EACC,gBAAA;E3ByEF,+BAAA;EACC,8BAAA;;A2BxFH,gBAmBE;EACE,YAAA;;AApBJ,gBAsBE,SAAS;EACP,iBAAA;;AAUJ,CAAC;EACC,cAAA;;AADF,CAAC,gBAGC;EACE,cAAA;;AAIF,CARD,gBAQE;AACD,CATD,gBASE;EACC,qBAAA;EACA,yBAAA;;AAIF,CAfD,gBAeE;AACD,CAhBD,gBAgBE,OAAO;AACR,CAjBD,gBAiBE,OAAO;EACN,UAAA;EACA,cAAA;EACA,yBAAA;EACA,qBAAA;;AANF,CAfD,gBAeE,OASC;AARF,CAhBD,gBAgBE,OAAO,MAQN;AAPF,CAjBD,gBAiBE,OAAO,MAON;EACE,cAAA;;AAVJ,CAfD,gBAeE,OAYC;AAXF,CAhBD,gBAgBE,OAAO,MAWN;AAVF,CAjBD,gBAiBE,OAAO,MAUN;EACE,cAAA;;A3BoYJ,iBAAiB;EACf,cAAA;EACA,yBAAA;;AAEA,CAAC,iBAJc;EAKb,cAAA;;AADF,CAAC,iBAJc,OAOb;EAA2B,cAAA;;AAE3B,CALD,iBAJc,OASZ;AACD,CAND,iBAJc,OAUZ;EACC,cAAA;EACA,yBAAA;;AAEF,CAVD,iBAJc,OAcZ;AACD,CAXD,iBAJc,OAeZ,OAAO;AACR,CAZD,iBAJc,OAgBZ,OAAO;EACN,WAAA;EACA,yBAAA;EACA,qBAAA;;AAnBN,iBAAiB;EACf,cAAA;EACA,yBAAA;;AAEA,CAAC,iBAJc;EAKb,cAAA;;AADF,CAAC,iBAJc,IAOb;EAA2B,cAAA;;AAE3B,CALD,iBAJc,IASZ;AACD,CAND,iBAJc,IAUZ;EACC,cAAA;EACA,yBAAA;;AAEF,CAVD,iBAJc,IAcZ;AACD,CAXD,iBAJc,IAeZ,OAAO;AACR,CAZD,iBAJc,IAgBZ,OAAO;EACN,WAAA;EACA,yBAAA;EACA,qBAAA;;AAnBN,iBAAiB;EACf,cAAA;EACA,yBAAA;;AAEA,CAAC,iBAJc;EAKb,cAAA;;AADF,CAAC,iBAJc,OAOb;EAA2B,cAAA;;AAE3B,CALD,iBAJc,OASZ;AACD,CAND,iBAJc,OAUZ;EACC,cAAA;EACA,yBAAA;;AAEF,CAVD,iBAJc,OAcZ;AACD,CAXD,iBAJc,OAeZ,OAAO;AACR,CAZD,iBAJc,OAgBZ,OAAO;EACN,WAAA;EACA,yBAAA;EACA,qBAAA;;AAnBN,iBAAiB;EACf,cAAA;EACA,yBAAA;;AAEA,CAAC,iBAJc;EAKb,cAAA;;AADF,CAAC,iBAJc,MAOb;EAA2B,cAAA;;AAE3B,CALD,iBAJc,MASZ;AACD,CAND,iBAJc,MAUZ;EACC,cAAA;EACA,yBAAA;;AAEF,CAVD,iBAJc,MAcZ;AACD,CAXD,iBAJc,MAeZ,OAAO;AACR,CAZD,iBAJc,MAgBZ,OAAO;EACN,WAAA;EACA,yBAAA;EACA,qBAAA;;A2BlYR;EACE,aAAA;EACA,kBAAA;;AAEF;EACE,gBAAA;EACA,gBAAA;;ACtGF;EACE,mBAAA;EACA,yBAAA;EACA,6BAAA;EACA,kBAAA;E5B+GA,iDAAA;EACQ,yCAAA;;A4B3GV;EACE,aAAA;;AAKF;EACE,kBAAA;EACA,oCAAA;E5B4EA,4BAAA;EACC,2BAAA;;A4B/EH,cAKE,YAAY;EACV,cAAA;;AAKJ;EACE,aAAA;EACA,gBAAA;EACA,eAAA;EACA,cAAA;;AAJF,YAME;EACE,cAAA;;AAKJ;EACE,kBAAA;EACA,yBAAA;EACA,6BAAA;E5B4DA,+BAAA;EACC,8BAAA;;A4BnDH,MACE;EACE,gBAAA;;AAFJ,MACE,cAGE;EACE,mBAAA;EACA,gBAAA;;AAIF,MATF,cASG,YACC,iBAAgB;EACd,aAAA;E5B8BN,4BAAA;EACC,2BAAA;;A4B1BC,MAhBF,cAgBG,WACC,iBAAgB;EACd,gBAAA;E5B+BN,+BAAA;EACC,8BAAA;;A4BzBH,cAAe,cACb,iBAAgB;EACd,mBAAA;;AAUJ,MACE;AADF,MAEE,oBAAoB;EAClB,gBAAA;;AAHJ,MAME,SAAQ;AANV,MAOE,oBAAmB,YAAa,SAAQ;E5BHxC,4BAAA;EACC,2BAAA;;A4BLH,MAME,SAAQ,YAIN,QAAO,YAEL,KAAI,YACF,GAAE;AAbV,MAOE,oBAAmB,YAAa,SAAQ,YAGtC,QAAO,YAEL,KAAI,YACF,GAAE;AAbV,MAME,SAAQ,YAKN,QAAO,YACL,KAAI,YACF,GAAE;AAbV,MAOE,oBAAmB,YAAa,SAAQ,YAItC,QAAO,YACL,KAAI,YACF,GAAE;AAbV,MAME,SAAQ,YAIN,QAAO,YAEL,KAAI,YAEF,GAAE;AAdV,MAOE,oBAAmB,YAAa,SAAQ,YAGtC,QAAO,YAEL,KAAI,YAEF,GAAE;AAdV,MAME,SAAQ,YAKN,QAAO,YACL,KAAI,YAEF,GAAE;AAdV,MAOE,oBAAmB,YAAa,SAAQ,YAItC,QAAO,YACL,KAAI,YAEF,GAAE;EACA,2BAAA;;AAfV,MAME,SAAQ,YAIN,QAAO,YAEL,KAAI,YAKF,GAAE;AAjBV,MAOE,oBAAmB,YAAa,SAAQ,YAGtC,QAAO,YAEL,KAAI,YAKF,GAAE;AAjBV,MAME,SAAQ,YAKN,QAAO,YACL,KAAI,YAKF,GAAE;AAjBV,MAOE,oBAAmB,YAAa,SAAQ,YAItC,QAAO,YACL,KAAI,YAKF,GAAE;AAjBV,MAME,SAAQ,YAIN,QAAO,YAEL,KAAI,YAMF,GAAE;AAlBV,MAOE,oBAAmB,YAAa,SAAQ,YAGtC,QAAO,YAEL,KAAI,YAMF,GAAE;AAlBV,MAME,SAAQ,YAKN,QAAO,YACL,KAAI,YAMF,GAAE;AAlBV,MAOE,oBAAmB,YAAa,SAAQ,YAItC,QAAO,YACL,KAAI,YAMF,GAAE;EACA,4BAAA;;AAnBV,MAyBE,SAAQ;AAzBV,MA0BE,oBAAmB,WAAY,SAAQ;E5BdvC,+BAAA;EACC,8BAAA;;A4BbH,MAyBE,SAAQ,WAIN,QAAO,WAEL,KAAI,WACF,GAAE;AAhCV,MA0BE,oBAAmB,WAAY,SAAQ,WAGrC,QAAO,WAEL,KAAI,WACF,GAAE;AAhCV,MAyBE,SAAQ,WAKN,QAAO,WACL,KAAI,WACF,GAAE;AAhCV,MA0BE,oBAAmB,WAAY,SAAQ,WAIrC,QAAO,WACL,KAAI,WACF,GAAE;AAhCV,MAyBE,SAAQ,WAIN,QAAO,WAEL,KAAI,WAEF,GAAE;AAjCV,MA0BE,oBAAmB,WAAY,SAAQ,WAGrC,QAAO,WAEL,KAAI,WAEF,GAAE;AAjCV,MAyBE,SAAQ,WAKN,QAAO,WACL,KAAI,WAEF,GAAE;AAjCV,MA0BE,oBAAmB,WAAY,SAAQ,WAIrC,QAAO,WACL,KAAI,WAEF,GAAE;EACA,8BAAA;;AAlCV,MAyBE,SAAQ,WAIN,QAAO,WAEL,KAAI,WAKF,GAAE;AApCV,MA0BE,oBAAmB,WAAY,SAAQ,WAGrC,QAAO,WAEL,KAAI,WAKF,GAAE;AApCV,MAyBE,SAAQ,WAKN,QAAO,WACL,KAAI,WAKF,GAAE;AApCV,MA0BE,oBAAmB,WAAY,SAAQ,WAIrC,QAAO,WACL,KAAI,WAKF,GAAE;AApCV,MAyBE,SAAQ,WAIN,QAAO,WAEL,KAAI,WAMF,GAAE;AArCV,MA0BE,oBAAmB,WAAY,SAAQ,WAGrC,QAAO,WAEL,KAAI,WAMF,GAAE;AArCV,MAyBE,SAAQ,WAKN,QAAO,WACL,KAAI,WAMF,GAAE;AArCV,MA0BE,oBAAmB,WAAY,SAAQ,WAIrC,QAAO,WACL,KAAI,WAMF,GAAE;EACA,+BAAA;;AAtCV,MA2CE,cAAc;AA3ChB,MA4CE,cAAc;EACZ,6BAAA;;AA7CJ,MA+CE,SAAS,QAAO,YAAa,KAAI,YAAa;AA/ChD,MAgDE,SAAS,QAAO,YAAa,KAAI,YAAa;EAC5C,aAAA;;AAjDJ,MAmDE;AAnDF,MAoDE,oBAAoB;EAClB,SAAA;;AArDJ,MAmDE,kBAGE,QAGE,KACE,KAAI;AA1DZ,MAoDE,oBAAoB,kBAElB,QAGE,KACE,KAAI;AA1DZ,MAmDE,kBAIE,QAEE,KACE,KAAI;AA1DZ,MAoDE,oBAAoB,kBAGlB,QAEE,KACE,KAAI;AA1DZ,MAmDE,kBAKE,QACE,KACE,KAAI;AA1DZ,MAoDE,oBAAoB,kBAIlB,QACE,KACE,KAAI;AA1DZ,MAmDE,kBAGE,QAGE,KAEE,KAAI;AA3DZ,MAoDE,oBAAoB,kBAElB,QAGE,KAEE,KAAI;AA3DZ,MAmDE,kBAIE,QAEE,KAEE,KAAI;AA3DZ,MAoDE,oBAAoB,kBAGlB,QAEE,KAEE,KAAI;AA3DZ,MAmDE,kBAKE,QACE,KAEE,KAAI;AA3DZ,MAoDE,oBAAoB,kBAIlB,QACE,KAEE,KAAI;EACF,cAAA;;AA5DV,MAmDE,kBAGE,QAGE,KAKE,KAAI;AA9DZ,MAoDE,oBAAoB,kBAElB,QAGE,KAKE,KAAI;AA9DZ,MAmDE,kBAIE,QAEE,KAKE,KAAI;AA9DZ,MAoDE,oBAAoB,kBAGlB,QAEE,KAKE,KAAI;AA9DZ,MAmDE,kBAKE,QACE,KAKE,KAAI;AA9DZ,MAoDE,oBAAoB,kBAIlB,QACE,KAKE,KAAI;AA9DZ,MAmDE,kBAGE,QAGE,KAME,KAAI;AA/DZ,MAoDE,oBAAoB,kBAElB,QAGE,KAME,KAAI;AA/DZ,MAmDE,kBAIE,QAEE,KAME,KAAI;AA/DZ,MAoDE,oBAAoB,kBAGlB,QAEE,KAME,KAAI;AA/DZ,MAmDE,kBAKE,QACE,KAME,KAAI;AA/DZ,MAoDE,oBAAoB,kBAIlB,QACE,KAME,KAAI;EACF,eAAA;;AAhEV,MAmDE,kBAiBE,QAEE,KAAI,YACF;AAvER,MAoDE,oBAAoB,kBAgBlB,QAEE,KAAI,YACF;AAvER,MAmDE,kBAkBE,QACE,KAAI,YACF;AAvER,MAoDE,oBAAoB,kBAiBlB,QACE,KAAI,YACF;AAvER,MAmDE,kBAiBE,QAEE,KAAI,YAEF;AAxER,MAoDE,oBAAoB,kBAgBlB,QAEE,KAAI,YAEF;AAxER,MAmDE,kBAkBE,QACE,KAAI,YAEF;AAxER,MAoDE,oBAAoB,kBAiBlB,QACE,KAAI,YAEF;EACE,gBAAA;;AAzEV,MAmDE,kBA0BE,QAEE,KAAI,WACF;AAhFR,MAoDE,oBAAoB,kBAyBlB,QAEE,KAAI,WACF;AAhFR,MAmDE,kBA2BE,QACE,KAAI,WACF;AAhFR,MAoDE,oBAAoB,kBA0BlB,QACE,KAAI,WACF;AAhFR,MAmDE,kBA0BE,QAEE,KAAI,WAEF;AAjFR,MAoDE,oBAAoB,kBAyBlB,QAEE,KAAI,WAEF;AAjFR,MAmDE,kBA2BE,QACE,KAAI,WAEF;AAjFR,MAoDE,oBAAoB,kBA0BlB,QACE,KAAI,WAEF;EACE,gBAAA;;AAlFV,MAuFE;EACE,SAAA;EACA,gBAAA;;AAUJ;EACE,mBAAA;;AADF,YAIE;EACE,gBAAA;EACA,kBAAA;EACA,gBAAA;;AAPJ,YAIE,OAIE;EACE,eAAA;;AATN,YAaE;EACE,gBAAA;;AAdJ,YAaE,eAEE,kBAAkB;EAChB,6BAAA;;AAhBN,YAmBE;EACE,aAAA;;AApBJ,YAmBE,cAEE,kBAAkB;EAChB,gCAAA;;AAON;E5BsLE,qBAAA;;AAEA,cAAE;EACA,cAAA;EACA,yBAAA;EACA,qBAAA;;AAHF,cAAE,iBAKA,kBAAkB;EAChB,yBAAA;;AAGJ,cAAE,gBACA,kBAAkB;EAChB,4BAAA;;A4BhMN;E5BmLE,qBAAA;;AAEA,cAAE;EACA,cAAA;EACA,yBAAA;EACA,qBAAA;;AAHF,cAAE,iBAKA,kBAAkB;EAChB,yBAAA;;AAGJ,cAAE,gBACA,kBAAkB;EAChB,4BAAA;;A4B7LN;E5BgLE,qBAAA;;AAEA,cAAE;EACA,cAAA;EACA,yBAAA;EACA,qBAAA;;AAHF,cAAE,iBAKA,kBAAkB;EAChB,yBAAA;;AAGJ,cAAE,gBACA,kBAAkB;EAChB,4BAAA;;A4B1LN;E5B6KE,qBAAA;;AAEA,WAAE;EACA,cAAA;EACA,yBAAA;EACA,qBAAA;;AAHF,WAAE,iBAKA,kBAAkB;EAChB,yBAAA;;AAGJ,WAAE,gBACA,kBAAkB;EAChB,4BAAA;;A4BvLN;E5B0KE,qBAAA;;AAEA,cAAE;EACA,cAAA;EACA,yBAAA;EACA,qBAAA;;AAHF,cAAE,iBAKA,kBAAkB;EAChB,yBAAA;;AAGJ,cAAE,gBACA,kBAAkB;EAChB,4BAAA;;A4BpLN;E5BuKE,qBAAA;;AAEA,aAAE;EACA,cAAA;EACA,yBAAA;EACA,qBAAA;;AAHF,aAAE,iBAKA,kBAAkB;EAChB,yBAAA;;AAGJ,aAAE,gBACA,kBAAkB;EAChB,4BAAA;;A6B5ZN;EACE,gBAAA;EACA,aAAA;EACA,mBAAA;EACA,yBAAA;EACA,yBAAA;EACA,kBAAA;E7B6GA,uDAAA;EACQ,+CAAA;;A6BpHV,KAQE;EACE,kBAAA;EACA,iCAAA;;AAKJ;EACE,aAAA;EACA,kBAAA;;AAEF;EACE,YAAA;EACA,kBAAA;;ACtBF;EACE,YAAA;EACA,eAAA;EACA,iBAAA;EACA,cAAA;EACA,cAAA;EACA,4BAAA;E9BkRA,YAAA;EAGA,yBAAA;;A8BlRA,MAAC;AACD,MAAC;EACC,cAAA;EACA,qBAAA;EACA,eAAA;E9B2QF,YAAA;EAGA,yBAAA;;A8BvQA,MAAM;EACJ,UAAA;EACA,eAAA;EACA,uBAAA;EACA,SAAA;EACA,wBAAA;;ACpBJ;EACE,gBAAA;;AAIF;EACE,aAAA;EACA,cAAA;EACA,kBAAA;EACA,eAAA;EACA,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,aAAA;EACA,iCAAA;EAIA,UAAA;;AAGA,MAAC,KAAM;E/BiIP,mBAAmB,kBAAnB;EACI,eAAe,kBAAf;EACI,WAAW,kBAAX;EApBR,mDAAA;EACG,6CAAA;EACE,yCAAA;EACG,mCAAA;;A+B9GR,MAAC,GAAI;E/B6HL,mBAAmB,eAAnB;EACI,eAAe,eAAf;EACI,WAAW,eAAX;;A+B3HV;EACE,kBAAA;EACA,WAAA;EACA,YAAA;;AAIF;EACE,kBAAA;EACA,yBAAA;EACA,yBAAA;EACA,oCAAA;EACA,kBAAA;E/BqEA,gDAAA;EACQ,wCAAA;E+BpER,4BAAA;EAEA,aAAA;;AAIF;EACE,eAAA;EACA,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,aAAA;EACA,yBAAA;;AAEA,eAAC;E/BwND,UAAA;EAGA,wBAAA;;A+B1NA,eAAC;E/BuND,YAAA;EAGA,yBAAA;;A+BrNF;EACE,aAAA;EACA,gCAAA;EACA,yBAAA;;AAGF,aAAc;EACZ,gBAAA;;AAIF;EACE,SAAA;EACA,uBAAA;;AAKF;EACE,kBAAA;EACA,aAAA;;AAIF;EACE,gBAAA;EACA,uBAAA;EACA,iBAAA;EACA,6BAAA;;AAJF,aAQE,KAAK;EACH,gBAAA;EACA,gBAAA;;AAVJ,aAaE,WAAW,KAAK;EACd,iBAAA;;AAdJ,aAiBE,WAAW;EACT,cAAA;;AAmBJ,QAdmC;EAEjC;IACE,YAAA;IACA,iBAAA;;EAEF;I/BPA,iDAAA;IACQ,yCAAA;;E+BWR;IAAY,YAAA;;;AAMd,QAHmC;EACjC;IAAY,YAAA;;;ACnId;EACE,kBAAA;EACA,aAAA;EACA,cAAA;EACA,mBAAA;EACA,eAAA;EACA,gBAAA;EhCiRA,UAAA;EAGA,wBAAA;;AgCjRA,QAAC;EhC8QD,YAAA;EAGA,yBAAA;;AgChRA,QAAC;EAAU,gBAAA;EAAmB,cAAA;;AAC9B,QAAC;EAAU,gBAAA;EAAmB,cAAA;;AAC9B,QAAC;EAAU,eAAA;EAAmB,cAAA;;AAC9B,QAAC;EAAU,iBAAA;EAAmB,cAAA;;AAIhC;EACE,gBAAA;EACA,gBAAA;EACA,cAAA;EACA,kBAAA;EACA,qBAAA;EACA,yBAAA;EACA,kBAAA;;AAIF;EACE,kBAAA;EACA,QAAA;EACA,SAAA;EACA,yBAAA;EACA,mBAAA;;AAGA,QAAC,IAAK;EACJ,SAAA;EACA,SAAA;EACA,iBAAA;EACA,uBAAA;EACA,yBAAA;;AAEF,QAAC,SAAU;EACT,SAAA;EACA,SAAA;EACA,uBAAA;EACA,yBAAA;;AAEF,QAAC,UAAW;EACV,SAAA;EACA,UAAA;EACA,uBAAA;EACA,yBAAA;;AAEF,QAAC,MAAO;EACN,QAAA;EACA,OAAA;EACA,gBAAA;EACA,2BAAA;EACA,2BAAA;;AAEF,QAAC,KAAM;EACL,QAAA;EACA,QAAA;EACA,gBAAA;EACA,2BAAA;EACA,0BAAA;;AAEF,QAAC,OAAQ;EACP,MAAA;EACA,SAAA;EACA,iBAAA;EACA,uBAAA;EACA,4BAAA;;AAEF,QAAC,YAAa;EACZ,MAAA;EACA,SAAA;EACA,uBAAA;EACA,4BAAA;;AAEF,QAAC,aAAc;EACb,MAAA;EACA,UAAA;EACA,uBAAA;EACA,4BAAA;;ACvFJ;EACE,kBAAA;EACA,MAAA;EACA,OAAA;EACA,aAAA;EACA,aAAA;EACA,gBAAA;EACA,YAAA;EACA,gBAAA;EACA,yBAAA;EACA,4BAAA;EACA,yBAAA;EACA,oCAAA;EACA,kBAAA;EjCuGA,iDAAA;EACQ,yCAAA;EiCpGR,mBAAA;;AAGA,QAAC;EAAW,iBAAA;;AACZ,QAAC;EAAW,iBAAA;;AACZ,QAAC;EAAW,gBAAA;;AACZ,QAAC;EAAW,kBAAA;;AAGd;EACE,SAAA;EACA,iBAAA;EACA,eAAA;EACA,mBAAA;EACA,iBAAA;EACA,yBAAA;EACA,gCAAA;EACA,0BAAA;;AAGF;EACE,iBAAA;;AAQA,QADO;AAEP,QAFO,SAEN;EACC,kBAAA;EACA,cAAA;EACA,QAAA;EACA,SAAA;EACA,yBAAA;EACA,mBAAA;;AAGJ,QAAS;EACP,kBAAA;;AAEF,QAAS,SAAQ;EACf,kBAAA;EACA,SAAS,EAAT;;AAIA,QAAC,IAAK;EACJ,SAAA;EACA,kBAAA;EACA,sBAAA;EACA,yBAAA;EACA,qCAAA;EACA,aAAA;;AACA,QAPD,IAAK,SAOH;EACC,SAAS,GAAT;EACA,WAAA;EACA,kBAAA;EACA,sBAAA;EACA,yBAAA;;AAGJ,QAAC,MAAO;EACN,QAAA;EACA,WAAA;EACA,iBAAA;EACA,oBAAA;EACA,2BAAA;EACA,uCAAA;;AACA,QAPD,MAAO,SAOL;EACC,SAAS,GAAT;EACA,SAAA;EACA,aAAA;EACA,oBAAA;EACA,2BAAA;;AAGJ,QAAC,OAAQ;EACP,SAAA;EACA,kBAAA;EACA,mBAAA;EACA,4BAAA;EACA,wCAAA;EACA,UAAA;;AACA,QAPD,OAAQ,SAON;EACC,SAAS,GAAT;EACA,QAAA;EACA,kBAAA;EACA,mBAAA;EACA,4BAAA;;AAIJ,QAAC,KAAM;EACL,QAAA;EACA,YAAA;EACA,iBAAA;EACA,qBAAA;EACA,0BAAA;EACA,sCAAA;;AACA,QAPD,KAAM,SAOJ;EACC,SAAS,GAAT;EACA,UAAA;EACA,qBAAA;EACA,0BAAA;EACA,aAAA;;A9B1HN;EACE,kBAAA;;AAGF;EACE,kBAAA;EACA,gBAAA;EACA,WAAA;;AAHF,eAKE;EACE,aAAA;EACA,kBAAA;EH8GF,yCAAA;EACQ,iCAAA;;AGtHV,eAKE,QAME;AAXJ,eAKE,QAOE,IAAI;EAEF,cAAA;;AAdN,eAkBE;AAlBF,eAmBE;AAnBF,eAoBE;EAAU,cAAA;;AApBZ,eAsBE;EACE,OAAA;;AAvBJ,eA0BE;AA1BF,eA2BE;EACE,kBAAA;EACA,MAAA;EACA,WAAA;;AA9BJ,eAiCE;EACE,UAAA;;AAlCJ,eAoCE;EACE,WAAA;;AArCJ,eAuCE,QAAO;AAvCT,eAwCE,QAAO;EACL,OAAA;;AAzCJ,eA4CE,UAAS;EACP,WAAA;;AA7CJ,eA+CE,UAAS;EACP,UAAA;;AAQJ;EACE,kBAAA;EACA,MAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EHsNA,YAAA;EAGA,yBAAA;EGvNA,eAAA;EACA,cAAA;EACA,kBAAA;EACA,yCAAA;;AAKA,iBAAC;EH8NC,kBAAkB,8BAA8B,mCAAyC,uCAAzF;EACA,kBAAmB,4EAAnB;EACA,2BAAA;EACA,sHAAA;;AG9NF,iBAAC;EACC,UAAA;EACA,QAAA;EHyNA,kBAAkB,8BAA8B,sCAAyC,oCAAzF;EACA,kBAAmB,4EAAnB;EACA,2BAAA;EACA,sHAAA;;AGvNF,iBAAC;AACD,iBAAC;EACC,aAAA;EACA,cAAA;EACA,qBAAA;EH8LF,YAAA;EAGA,yBAAA;;AG9NF,iBAkCE;AAlCF,iBAmCE;AAnCF,iBAoCE;AApCF,iBAqCE;EACE,kBAAA;EACA,QAAA;EACA,UAAA;EACA,qBAAA;;AAzCJ,iBA2CE;AA3CF,iBA4CE;EACE,SAAA;;AA7CJ,iBA+CE;AA/CF,iBAgDE;EACE,UAAA;;AAjDJ,iBAmDE;AAnDF,iBAoDE;EACE,WAAA;EACA,YAAA;EACA,iBAAA;EACA,kBAAA;EACA,kBAAA;;AAIA,iBADF,WACG;EACC,SAAS,OAAT;;AAIF,iBADF,WACG;EACC,SAAS,OAAT;;AAUN;EACE,kBAAA;EACA,YAAA;EACA,SAAA;EACA,WAAA;EACA,UAAA;EACA,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,kBAAA;;AATF,oBAWE;EACE,qBAAA;EACA,WAAA;EACA,YAAA;EACA,WAAA;EACA,mBAAA;EACA,yBAAA;EACA,mBAAA;EACA,eAAA;EAUA,yBAAA;EACA,kCAAA;;AA9BJ,oBAgCE;EACE,SAAA;EACA,WAAA;EACA,YAAA;EACA,yBAAA;;AAOJ;EACE,kBAAA;EACA,SAAA;EACA,UAAA;EACA,YAAA;EACA,WAAA;EACA,iBAAA;EACA,oBAAA;EACA,cAAA;EACA,kBAAA;EACA,yCAAA;;AACA,iBAAE;EACA,iBAAA;;AAkCJ,mBA5B8C;EAG5C,iBACE;EADF,iBAEE;EAFF,iBAGE;EAHF,iBAIE;IACE,WAAA;IACA,YAAA;IACA,iBAAA;IACA,kBAAA;IACA,eAAA;;EAKJ;IACE,SAAA;IACA,UAAA;IACA,oBAAA;;EAIF;IACE,YAAA;;;AHlNF,SAAC;AACD,SAAC;AMXH,UNUG;AMVH,UNWG;AMSH,gBNVG;AMUH,gBNTG;AMkBH,INnBG;AMmBH,INlBG;AQsXH,gBAoBE,YR3YC;AQuXH,gBAoBE,YR1YC;AUkBH,YVnBG;AUmBH,YVlBG;AU8HH,mBAWE,aV1IC;AU+HH,mBAWE,aVzIC;AeZH,IfWG;AeXH,IfYG;AgBVH,OhBSG;AgBTH,OhBUG;AgBUH,chBXG;AgBWH,chBVG;AgB6BH,gBhB9BG;AgB8BH,gBhB7BG;AoBfH,MpBcG;AoBdH,MpBeG;A4BLH,W5BIG;A4BJH,W5BKG;A+B+EH,a/BhFG;A+BgFH,a/B/EG;EACC,SAAS,GAAT;EACA,cAAA;;AAEF,SAAC;AMfH,UNeG;AMKH,gBNLG;AMcH,INdG;AQkXH,gBAoBE,YRtYC;AUcH,YVdG;AU0HH,mBAWE,aVrIC;AehBH,IfgBG;AgBdH,OhBcG;AgBMH,chBNG;AgByBH,gBhBzBG;AoBnBH,MpBmBG;A4BTH,W5BSG;A+B2EH,a/B3EG;EACC,WAAA;;AiBdJ;EjB6BE,cAAA;EACA,iBAAA;EACA,kBAAA;;AiB5BF;EACE,uBAAA;;AAEF;EACE,sBAAA;;AAQF;EACE,wBAAA;;AAEF;EACE,yBAAA;;AAEF;EACE,kBAAA;;AAEF;EjB8CE,WAAA;EACA,kBAAA;EACA,iBAAA;EACA,6BAAA;EACA,SAAA;;AiBzCF;EACE,wBAAA;EACA,6BAAA;;AAOF;EACE,eAAA;;AiBnCF;EACE,mBAAA;;AAKF;AACA;AACA;AACA;ElCylBE,wBAAA;;AkCjlBF,QAHqC;EAGrC;IlCykBE,yBAAA;;EACA,KAAK;IAAK,cAAA;;EACV,EAAE;IAAQ,kBAAA;;EACV,EAAE;EACF,EAAE;IAAQ,mBAAA;;;AkCxkBZ,QAHqC,uBAAgC;EAGrE;IlCokBE,yBAAA;;EACA,KAAK;IAAK,cAAA;;EACV,EAAE;IAAQ,kBAAA;;EACV,EAAE;EACF,EAAE;IAAQ,mBAAA;;;AkCnkBZ,QAHqC,uBAAgC;EAGrE;IlC+jBE,yBAAA;;EACA,KAAK;IAAK,cAAA;;EACV,EAAE;IAAQ,kBAAA;;EACV,EAAE;EACF,EAAE;IAAQ,mBAAA;;;AkC9jBZ,QAHqC;EAGrC;IlC0jBE,yBAAA;;EACA,KAAK;IAAK,cAAA;;EACV,EAAE;IAAQ,kBAAA;;EACV,EAAE;EACF,EAAE;IAAQ,mBAAA;;;AkCxjBZ,QAHqC;EAGrC;IlC4jBE,wBAAA;;;AkCvjBF,QAHqC,uBAAgC;EAGrE;IlCujBE,wBAAA;;;AkCljBF,QAHqC,uBAAgC;EAGrE;IlCkjBE,wBAAA;;;AkC7iBF,QAHqC;EAGrC;IlC6iBE,wBAAA;;;AkCtiBF;ElCsiBE,wBAAA;;AkChiBF;EAAA;IlCwhBE,yBAAA;;EACA,KAAK;IAAK,cAAA;;EACV,EAAE;IAAQ,kBAAA;;EACV,EAAE;EACF,EAAE;IAAQ,mBAAA;;;AkCthBZ;EAAA;IlC0hBE,wBAAA","sourcesContent":["/*! normalize.css v3.0.0 | MIT License | git.io/normalize */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS text size adjust after orientation change, without disabling\n// user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined in IE 8/9.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9.\n// Hide the `template` element in IE, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background: transparent;\n}\n\n//\n// Improve readability when focused and also mouse hovered in all browsers.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9, Safari 5, and Chrome.\n//\n\nabbr[title] {\n border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari 5 and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari 5, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow displayed oddly in IE 9.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari 5.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8+, and Opera\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome\n// (include `-moz` to future-proof).\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n -moz-box-sizing: content-box;\n -webkit-box-sizing: content-box; // 2\n box-sizing: content-box;\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}","//\n// Basic print styles\n// --------------------------------------------------\n// Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css\n\n@media print {\n\n * {\n text-shadow: none !important;\n color: #000 !important; // Black prints faster: h5bp.com/s\n background: transparent !important;\n box-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links for images, or javascript/internal links\n a[href^=\"javascript:\"]:after,\n a[href^=\"#\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Chrome (OSX) fix for https://github.com/twbs/bootstrap/issues/11245\n // Once fixed, we can just straight up remove this.\n select {\n background: #fff !important;\n }\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .table {\n td,\n th {\n background-color: #fff !important;\n }\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n\n}\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 62.5%;\n -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: underline;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0,0,0,0);\n border: 0;\n}\n","//\n// Mixins\n// --------------------------------------------------\n\n\n// Utilities\n// -------------------------\n\n// Clearfix\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n.clearfix() {\n &:before,\n &:after {\n content: \" \"; // 1\n display: table; // 2\n }\n &:after {\n clear: both;\n }\n}\n\n// WebKit-style focus\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n\n// Center-align a block level element\n.center-block() {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n\n// Sizing shortcuts\n.size(@width; @height) {\n width: @width;\n height: @height;\n}\n.square(@size) {\n .size(@size; @size);\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n &::-moz-placeholder { color: @color; // Firefox\n opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Text overflow\n// Requires inline-block or block for proper styling\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note\n// that we cannot chain the mixins together in Less, so they are repeated.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n\n\n\n// CSS3 PROPERTIES\n// --------------------------------------------------\n\n// Single side border-radius\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support the\n// standard `box-shadow` property.\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Transitions\n.transition(@transition) {\n -webkit-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n// Transformations\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n transform: rotate(@degrees);\n}\n.scale(@ratio; @ratio-y...) {\n -webkit-transform: scale(@ratio, @ratio-y);\n -ms-transform: scale(@ratio, @ratio-y); // IE9 only\n transform: scale(@ratio, @ratio-y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n transform: translate(@x, @y);\n}\n.skew(@x; @y) {\n -webkit-transform: skew(@x, @y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n transform: skew(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// User select\n// For selecting text on the page\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n\n// Resize anything\n.resizable(@direction) {\n resize: @direction; // Options: horizontal, vertical, both\n overflow: auto; // Safari fix\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Opacity\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n\n\n\n// GRADIENTS\n// --------------------------------------------------\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, color-stop(@start-color @start-percent), color-stop(@end-color @end-percent)); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n\n// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n\n\n\n// Retina images\n//\n// Short retina mixin for setting background-image and -size\n\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// COMPONENT MIXINS\n// --------------------------------------------------\n\n// Horizontal dividers\n// -------------------------\n// Dividers (basically an hr) within dropdowns and nav lists\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n\n// Panels\n// -------------------------\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse .panel-body {\n border-top-color: @border;\n }\n }\n & > .panel-footer {\n + .panel-collapse .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n\n// Alerts\n// -------------------------\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n\n// Tables\n// -------------------------\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n\n// List Groups\n// -------------------------\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a& {\n color: @color;\n\n .list-group-item-heading { color: inherit; }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n\n// Button variants\n// -------------------------\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:hover,\n &:focus,\n &:active,\n &.active,\n .open .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 8%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &:active,\n &.active {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n// -------------------------\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n\n// Pagination\n// -------------------------\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n\n// Labels\n// -------------------------\n.label-variant(@color) {\n background-color: @color;\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n\n// Contextual backgrounds\n// -------------------------\n.bg-variant(@color) {\n background-color: @color;\n a&:hover {\n background-color: darken(@color, 10%);\n }\n}\n\n// Typography\n// -------------------------\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover {\n color: darken(@color, 10%);\n }\n}\n\n// Navbar vertical align\n// -------------------------\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n\n// Progress bars\n// -------------------------\n.progress-bar-variant(@color) {\n background-color: @color;\n .progress-striped & {\n #gradient > .striped();\n }\n}\n\n// Responsive utilities\n// -------------------------\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n display: block !important;\n table& { display: table; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n\n\n// Grid System\n// -----------\n\n// Centered container element\n.container-fixed() {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: (@gutter / -2);\n margin-right: (@gutter / -2);\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n @media (min-width: @screen-xs-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-push(@columns) {\n @media (min-width: @screen-xs-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-pull(@columns) {\n @media (min-width: @screen-xs-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n\n// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n border-color: @border-color;\n background-color: @background-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-focus-border` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n","//\n// Variables\n// --------------------------------------------------\n\n\n//== Colors\n//\n//## Gray and brand colors for use across Bootstrap.\n\n@gray-darker: lighten(#000, 13.5%); // #222\n@gray-dark: lighten(#000, 20%); // #333\n@gray: lighten(#000, 33.5%); // #555\n@gray-light: lighten(#000, 60%); // #999\n@gray-lighter: lighten(#000, 93.5%); // #eee\n\n@brand-primary: #428bca;\n@brand-success: #5cb85c;\n@brand-info: #5bc0de;\n@brand-warning: #f0ad4e;\n@brand-danger: #d9534f;\n\n\n//== Scaffolding\n//\n// ## Settings for some of the most global styles.\n\n//** Background color for `<body>`.\n@body-bg: #fff;\n//** Global text color on `<body>`.\n@text-color: @gray-dark;\n\n//** Global textual link color.\n@link-color: @brand-primary;\n//** Link hover color set via `darken()` function.\n@link-hover-color: darken(@link-color, 15%);\n\n\n//== Typography\n//\n//## Font, line-height, and color for body text, headings, and more.\n\n@font-family-sans-serif: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n@font-family-serif: Georgia, \"Times New Roman\", Times, serif;\n//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.\n@font-family-monospace: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n@font-family-base: @font-family-sans-serif;\n\n@font-size-base: 14px;\n@font-size-large: ceil((@font-size-base * 1.25)); // ~18px\n@font-size-small: ceil((@font-size-base * 0.85)); // ~12px\n\n@font-size-h1: floor((@font-size-base * 2.6)); // ~36px\n@font-size-h2: floor((@font-size-base * 2.15)); // ~30px\n@font-size-h3: ceil((@font-size-base * 1.7)); // ~24px\n@font-size-h4: ceil((@font-size-base * 1.25)); // ~18px\n@font-size-h5: @font-size-base;\n@font-size-h6: ceil((@font-size-base * 0.85)); // ~12px\n\n//** Unit-less `line-height` for use in components like buttons.\n@line-height-base: 1.428571429; // 20/14\n//** Computed \"line-height\" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.\n@line-height-computed: floor((@font-size-base * @line-height-base)); // ~20px\n\n//** By default, this inherits from the `<body>`.\n@headings-font-family: inherit;\n@headings-font-weight: 500;\n@headings-line-height: 1.1;\n@headings-color: inherit;\n\n\n//-- Iconography\n//\n//## Specify custom locations of the include Glyphicons icon font. Useful for those including Bootstrap via Bower.\n\n@icon-font-path: \"../fonts/\";\n@icon-font-name: \"glyphicons-halflings-regular\";\n@icon-font-svg-id: \"glyphicons_halflingsregular\";\n\n//== Components\n//\n//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).\n\n@padding-base-vertical: 6px;\n@padding-base-horizontal: 12px;\n\n@padding-large-vertical: 10px;\n@padding-large-horizontal: 16px;\n\n@padding-small-vertical: 5px;\n@padding-small-horizontal: 10px;\n\n@padding-xs-vertical: 1px;\n@padding-xs-horizontal: 5px;\n\n@line-height-large: 1.33;\n@line-height-small: 1.5;\n\n@border-radius-base: 4px;\n@border-radius-large: 6px;\n@border-radius-small: 3px;\n\n//** Global color for active items (e.g., navs or dropdowns).\n@component-active-color: #fff;\n//** Global background color for active items (e.g., navs or dropdowns).\n@component-active-bg: @brand-primary;\n\n//** Width of the `border` for generating carets that indicator dropdowns.\n@caret-width-base: 4px;\n//** Carets increase slightly in size for larger components.\n@caret-width-large: 5px;\n\n\n//== Tables\n//\n//## Customizes the `.table` component with basic values, each used across all table variations.\n\n//** Padding for `<th>`s and `<td>`s.\n@table-cell-padding: 8px;\n//** Padding for cells in `.table-condensed`.\n@table-condensed-cell-padding: 5px;\n\n//** Default background color used for all tables.\n@table-bg: transparent;\n//** Background color used for `.table-striped`.\n@table-bg-accent: #f9f9f9;\n//** Background color used for `.table-hover`.\n@table-bg-hover: #f5f5f5;\n@table-bg-active: @table-bg-hover;\n\n//** Border color for table and cell borders.\n@table-border-color: #ddd;\n\n\n//== Buttons\n//\n//## For each of Bootstrap's buttons, define text, background and border color.\n\n@btn-font-weight: normal;\n\n@btn-default-color: #333;\n@btn-default-bg: #fff;\n@btn-default-border: #ccc;\n\n@btn-primary-color: #fff;\n@btn-primary-bg: @brand-primary;\n@btn-primary-border: darken(@btn-primary-bg, 5%);\n\n@btn-success-color: #fff;\n@btn-success-bg: @brand-success;\n@btn-success-border: darken(@btn-success-bg, 5%);\n\n@btn-info-color: #fff;\n@btn-info-bg: @brand-info;\n@btn-info-border: darken(@btn-info-bg, 5%);\n\n@btn-warning-color: #fff;\n@btn-warning-bg: @brand-warning;\n@btn-warning-border: darken(@btn-warning-bg, 5%);\n\n@btn-danger-color: #fff;\n@btn-danger-bg: @brand-danger;\n@btn-danger-border: darken(@btn-danger-bg, 5%);\n\n@btn-link-disabled-color: @gray-light;\n\n\n//== Forms\n//\n//##\n\n//** `<input>` background color\n@input-bg: #fff;\n//** `<input disabled>` background color\n@input-bg-disabled: @gray-lighter;\n\n//** Text color for `<input>`s\n@input-color: @gray;\n//** `<input>` border color\n@input-border: #ccc;\n//** `<input>` border radius\n@input-border-radius: @border-radius-base;\n//** Border color for inputs on focus\n@input-border-focus: #66afe9;\n\n//** Placeholder text color\n@input-color-placeholder: @gray-light;\n\n//** Default `.form-control` height\n@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);\n//** Large `.form-control` height\n@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);\n//** Small `.form-control` height\n@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);\n\n@legend-color: @gray-dark;\n@legend-border-color: #e5e5e5;\n\n//** Background color for textual input addons\n@input-group-addon-bg: @gray-lighter;\n//** Border color for textual input addons\n@input-group-addon-border-color: @input-border;\n\n\n//== Dropdowns\n//\n//## Dropdown menu container and contents.\n\n//** Background for the dropdown menu.\n@dropdown-bg: #fff;\n//** Dropdown menu `border-color`.\n@dropdown-border: rgba(0,0,0,.15);\n//** Dropdown menu `border-color` **for IE8**.\n@dropdown-fallback-border: #ccc;\n//** Divider color for between dropdown items.\n@dropdown-divider-bg: #e5e5e5;\n\n//** Dropdown link text color.\n@dropdown-link-color: @gray-dark;\n//** Hover color for dropdown links.\n@dropdown-link-hover-color: darken(@gray-dark, 5%);\n//** Hover background for dropdown links.\n@dropdown-link-hover-bg: #f5f5f5;\n\n//** Active dropdown menu item text color.\n@dropdown-link-active-color: @component-active-color;\n//** Active dropdown menu item background color.\n@dropdown-link-active-bg: @component-active-bg;\n\n//** Disabled dropdown menu item background color.\n@dropdown-link-disabled-color: @gray-light;\n\n//** Text color for headers within dropdown menus.\n@dropdown-header-color: @gray-light;\n\n// Note: Deprecated @dropdown-caret-color as of v3.1.0\n@dropdown-caret-color: #000;\n\n\n//-- Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n//\n// Note: These variables are not generated into the Customizer.\n\n@zindex-navbar: 1000;\n@zindex-dropdown: 1000;\n@zindex-popover: 1010;\n@zindex-tooltip: 1030;\n@zindex-navbar-fixed: 1030;\n@zindex-modal-background: 1040;\n@zindex-modal: 1050;\n\n\n//== Media queries breakpoints\n//\n//## Define the breakpoints at which your layout will change, adapting to different screen sizes.\n\n// Extra small screen / phone\n// Note: Deprecated @screen-xs and @screen-phone as of v3.0.1\n@screen-xs: 480px;\n@screen-xs-min: @screen-xs;\n@screen-phone: @screen-xs-min;\n\n// Small screen / tablet\n// Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1\n@screen-sm: 768px;\n@screen-sm-min: @screen-sm;\n@screen-tablet: @screen-sm-min;\n\n// Medium screen / desktop\n// Note: Deprecated @screen-md and @screen-desktop as of v3.0.1\n@screen-md: 992px;\n@screen-md-min: @screen-md;\n@screen-desktop: @screen-md-min;\n\n// Large screen / wide desktop\n// Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1\n@screen-lg: 1200px;\n@screen-lg-min: @screen-lg;\n@screen-lg-desktop: @screen-lg-min;\n\n// So media queries don't overlap when required, provide a maximum\n@screen-xs-max: (@screen-sm-min - 1);\n@screen-sm-max: (@screen-md-min - 1);\n@screen-md-max: (@screen-lg-min - 1);\n\n\n//== Grid system\n//\n//## Define your custom responsive grid.\n\n//** Number of columns in the grid.\n@grid-columns: 12;\n//** Padding between columns. Gets divided in half for the left and right.\n@grid-gutter-width: 30px;\n// Navbar collapse\n//** Point at which the navbar becomes uncollapsed.\n@grid-float-breakpoint: @screen-sm-min;\n//** Point at which the navbar begins collapsing.\n@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);\n\n\n//== Container sizes\n//\n//## Define the maximum width of `.container` for different screen sizes.\n\n// Small screen / tablet\n@container-tablet: ((720px + @grid-gutter-width));\n//** For `@screen-sm-min` and up.\n@container-sm: @container-tablet;\n\n// Medium screen / desktop\n@container-desktop: ((940px + @grid-gutter-width));\n//** For `@screen-md-min` and up.\n@container-md: @container-desktop;\n\n// Large screen / wide desktop\n@container-large-desktop: ((1140px + @grid-gutter-width));\n//** For `@screen-lg-min` and up.\n@container-lg: @container-large-desktop;\n\n\n//== Navbar\n//\n//##\n\n// Basics of a navbar\n@navbar-height: 50px;\n@navbar-margin-bottom: @line-height-computed;\n@navbar-border-radius: @border-radius-base;\n@navbar-padding-horizontal: floor((@grid-gutter-width / 2));\n@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);\n@navbar-collapse-max-height: 340px;\n\n@navbar-default-color: #777;\n@navbar-default-bg: #f8f8f8;\n@navbar-default-border: darken(@navbar-default-bg, 6.5%);\n\n// Navbar links\n@navbar-default-link-color: #777;\n@navbar-default-link-hover-color: #333;\n@navbar-default-link-hover-bg: transparent;\n@navbar-default-link-active-color: #555;\n@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%);\n@navbar-default-link-disabled-color: #ccc;\n@navbar-default-link-disabled-bg: transparent;\n\n// Navbar brand label\n@navbar-default-brand-color: @navbar-default-link-color;\n@navbar-default-brand-hover-color: darken(@navbar-default-brand-color, 10%);\n@navbar-default-brand-hover-bg: transparent;\n\n// Navbar toggle\n@navbar-default-toggle-hover-bg: #ddd;\n@navbar-default-toggle-icon-bar-bg: #888;\n@navbar-default-toggle-border-color: #ddd;\n\n\n// Inverted navbar\n// Reset inverted navbar basics\n@navbar-inverse-color: @gray-light;\n@navbar-inverse-bg: #222;\n@navbar-inverse-border: darken(@navbar-inverse-bg, 10%);\n\n// Inverted navbar links\n@navbar-inverse-link-color: @gray-light;\n@navbar-inverse-link-hover-color: #fff;\n@navbar-inverse-link-hover-bg: transparent;\n@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;\n@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%);\n@navbar-inverse-link-disabled-color: #444;\n@navbar-inverse-link-disabled-bg: transparent;\n\n// Inverted navbar brand label\n@navbar-inverse-brand-color: @navbar-inverse-link-color;\n@navbar-inverse-brand-hover-color: #fff;\n@navbar-inverse-brand-hover-bg: transparent;\n\n// Inverted navbar toggle\n@navbar-inverse-toggle-hover-bg: #333;\n@navbar-inverse-toggle-icon-bar-bg: #fff;\n@navbar-inverse-toggle-border-color: #333;\n\n\n//== Navs\n//\n//##\n\n//=== Shared nav styles\n@nav-link-padding: 10px 15px;\n@nav-link-hover-bg: @gray-lighter;\n\n@nav-disabled-link-color: @gray-light;\n@nav-disabled-link-hover-color: @gray-light;\n\n@nav-open-link-hover-color: #fff;\n\n//== Tabs\n@nav-tabs-border-color: #ddd;\n\n@nav-tabs-link-hover-border-color: @gray-lighter;\n\n@nav-tabs-active-link-hover-bg: @body-bg;\n@nav-tabs-active-link-hover-color: @gray;\n@nav-tabs-active-link-hover-border-color: #ddd;\n\n@nav-tabs-justified-link-border-color: #ddd;\n@nav-tabs-justified-active-link-border-color: @body-bg;\n\n//== Pills\n@nav-pills-border-radius: @border-radius-base;\n@nav-pills-active-link-hover-bg: @component-active-bg;\n@nav-pills-active-link-hover-color: @component-active-color;\n\n\n//== Pagination\n//\n//##\n\n@pagination-color: @link-color;\n@pagination-bg: #fff;\n@pagination-border: #ddd;\n\n@pagination-hover-color: @link-hover-color;\n@pagination-hover-bg: @gray-lighter;\n@pagination-hover-border: #ddd;\n\n@pagination-active-color: #fff;\n@pagination-active-bg: @brand-primary;\n@pagination-active-border: @brand-primary;\n\n@pagination-disabled-color: @gray-light;\n@pagination-disabled-bg: #fff;\n@pagination-disabled-border: #ddd;\n\n\n//== Pager\n//\n//##\n\n@pager-bg: @pagination-bg;\n@pager-border: @pagination-border;\n@pager-border-radius: 15px;\n\n@pager-hover-bg: @pagination-hover-bg;\n\n@pager-active-bg: @pagination-active-bg;\n@pager-active-color: @pagination-active-color;\n\n@pager-disabled-color: @pagination-disabled-color;\n\n\n//== Jumbotron\n//\n//##\n\n@jumbotron-padding: 30px;\n@jumbotron-color: inherit;\n@jumbotron-bg: @gray-lighter;\n@jumbotron-heading-color: inherit;\n@jumbotron-font-size: ceil((@font-size-base * 1.5));\n\n\n//== Form states and alerts\n//\n//## Define colors for form feedback states and, by default, alerts.\n\n@state-success-text: #3c763d;\n@state-success-bg: #dff0d8;\n@state-success-border: darken(spin(@state-success-bg, -10), 5%);\n\n@state-info-text: #31708f;\n@state-info-bg: #d9edf7;\n@state-info-border: darken(spin(@state-info-bg, -10), 7%);\n\n@state-warning-text: #8a6d3b;\n@state-warning-bg: #fcf8e3;\n@state-warning-border: darken(spin(@state-warning-bg, -10), 5%);\n\n@state-danger-text: #a94442;\n@state-danger-bg: #f2dede;\n@state-danger-border: darken(spin(@state-danger-bg, -10), 5%);\n\n\n//== Tooltips\n//\n//##\n\n//** Tooltip max width\n@tooltip-max-width: 200px;\n//** Tooltip text color\n@tooltip-color: #fff;\n//** Tooltip background color\n@tooltip-bg: #000;\n@tooltip-opacity: .9;\n\n//** Tooltip arrow width\n@tooltip-arrow-width: 5px;\n//** Tooltip arrow color\n@tooltip-arrow-color: @tooltip-bg;\n\n\n//== Popovers\n//\n//##\n\n//** Popover body background color\n@popover-bg: #fff;\n//** Popover maximum width\n@popover-max-width: 276px;\n//** Popover border color\n@popover-border-color: rgba(0,0,0,.2);\n//** Popover fallback border color\n@popover-fallback-border-color: #ccc;\n\n//** Popover title background color\n@popover-title-bg: darken(@popover-bg, 3%);\n\n//** Popover arrow width\n@popover-arrow-width: 10px;\n//** Popover arrow color\n@popover-arrow-color: #fff;\n\n//** Popover outer arrow width\n@popover-arrow-outer-width: (@popover-arrow-width + 1);\n//** Popover outer arrow color\n@popover-arrow-outer-color: fadein(@popover-border-color, 5%);\n//** Popover outer arrow fallback color\n@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%);\n\n\n//== Labels\n//\n//##\n\n//** Default label background color\n@label-default-bg: @gray-light;\n//** Primary label background color\n@label-primary-bg: @brand-primary;\n//** Success label background color\n@label-success-bg: @brand-success;\n//** Info label background color\n@label-info-bg: @brand-info;\n//** Warning label background color\n@label-warning-bg: @brand-warning;\n//** Danger label background color\n@label-danger-bg: @brand-danger;\n\n//** Default label text color\n@label-color: #fff;\n//** Default text color of a linked label\n@label-link-hover-color: #fff;\n\n\n//== Modals\n//\n//##\n\n//** Padding applied to the modal body\n@modal-inner-padding: 20px;\n\n//** Padding applied to the modal title\n@modal-title-padding: 15px;\n//** Modal title line-height\n@modal-title-line-height: @line-height-base;\n\n//** Background color of modal content area\n@modal-content-bg: #fff;\n//** Modal content border color\n@modal-content-border-color: rgba(0,0,0,.2);\n//** Modal content border color **for IE8**\n@modal-content-fallback-border-color: #999;\n\n//** Modal backdrop background color\n@modal-backdrop-bg: #000;\n//** Modal backdrop opacity\n@modal-backdrop-opacity: .5;\n//** Modal header border color\n@modal-header-border-color: #e5e5e5;\n//** Modal footer border color\n@modal-footer-border-color: @modal-header-border-color;\n\n@modal-lg: 900px;\n@modal-md: 600px;\n@modal-sm: 300px;\n\n\n//== Alerts\n//\n//## Define alert colors, border radius, and padding.\n\n@alert-padding: 15px;\n@alert-border-radius: @border-radius-base;\n@alert-link-font-weight: bold;\n\n@alert-success-bg: @state-success-bg;\n@alert-success-text: @state-success-text;\n@alert-success-border: @state-success-border;\n\n@alert-info-bg: @state-info-bg;\n@alert-info-text: @state-info-text;\n@alert-info-border: @state-info-border;\n\n@alert-warning-bg: @state-warning-bg;\n@alert-warning-text: @state-warning-text;\n@alert-warning-border: @state-warning-border;\n\n@alert-danger-bg: @state-danger-bg;\n@alert-danger-text: @state-danger-text;\n@alert-danger-border: @state-danger-border;\n\n\n//== Progress bars\n//\n//##\n\n//** Background color of the whole progress component\n@progress-bg: #f5f5f5;\n//** Progress bar text color\n@progress-bar-color: #fff;\n\n//** Default progress bar color\n@progress-bar-bg: @brand-primary;\n//** Success progress bar color\n@progress-bar-success-bg: @brand-success;\n//** Warning progress bar color\n@progress-bar-warning-bg: @brand-warning;\n//** Danger progress bar color\n@progress-bar-danger-bg: @brand-danger;\n//** Info progress bar color\n@progress-bar-info-bg: @brand-info;\n\n\n//== List group\n//\n//##\n\n//** Background color on `.list-group-item`\n@list-group-bg: #fff;\n//** `.list-group-item` border color\n@list-group-border: #ddd;\n//** List group border radius\n@list-group-border-radius: @border-radius-base;\n\n//** Background color of single list elements on hover\n@list-group-hover-bg: #f5f5f5;\n//** Text color of active list elements\n@list-group-active-color: @component-active-color;\n//** Background color of active list elements\n@list-group-active-bg: @component-active-bg;\n//** Border color of active list elements\n@list-group-active-border: @list-group-active-bg;\n@list-group-active-text-color: lighten(@list-group-active-bg, 40%);\n\n@list-group-link-color: #555;\n@list-group-link-heading-color: #333;\n\n\n//== Panels\n//\n//##\n\n@panel-bg: #fff;\n@panel-body-padding: 15px;\n@panel-border-radius: @border-radius-base;\n\n//** Border color for elements within panels\n@panel-inner-border: #ddd;\n@panel-footer-bg: #f5f5f5;\n\n@panel-default-text: @gray-dark;\n@panel-default-border: #ddd;\n@panel-default-heading-bg: #f5f5f5;\n\n@panel-primary-text: #fff;\n@panel-primary-border: @brand-primary;\n@panel-primary-heading-bg: @brand-primary;\n\n@panel-success-text: @state-success-text;\n@panel-success-border: @state-success-border;\n@panel-success-heading-bg: @state-success-bg;\n\n@panel-info-text: @state-info-text;\n@panel-info-border: @state-info-border;\n@panel-info-heading-bg: @state-info-bg;\n\n@panel-warning-text: @state-warning-text;\n@panel-warning-border: @state-warning-border;\n@panel-warning-heading-bg: @state-warning-bg;\n\n@panel-danger-text: @state-danger-text;\n@panel-danger-border: @state-danger-border;\n@panel-danger-heading-bg: @state-danger-bg;\n\n\n//== Thumbnails\n//\n//##\n\n//** Padding around the thumbnail image\n@thumbnail-padding: 4px;\n//** Thumbnail background color\n@thumbnail-bg: @body-bg;\n//** Thumbnail border color\n@thumbnail-border: #ddd;\n//** Thumbnail border radius\n@thumbnail-border-radius: @border-radius-base;\n\n//** Custom text color for thumbnail captions\n@thumbnail-caption-color: @text-color;\n//** Padding around the thumbnail caption\n@thumbnail-caption-padding: 9px;\n\n\n//== Wells\n//\n//##\n\n@well-bg: #f5f5f5;\n@well-border: darken(@well-bg, 7%);\n\n\n//== Badges\n//\n//##\n\n@badge-color: #fff;\n//** Linked badge text color on hover\n@badge-link-hover-color: #fff;\n@badge-bg: @gray-light;\n\n//** Badge text color in active nav link\n@badge-active-color: @link-color;\n//** Badge background color in active nav link\n@badge-active-bg: #fff;\n\n@badge-font-weight: bold;\n@badge-line-height: 1;\n@badge-border-radius: 10px;\n\n\n//== Breadcrumbs\n//\n//##\n\n@breadcrumb-padding-vertical: 8px;\n@breadcrumb-padding-horizontal: 15px;\n//** Breadcrumb background color\n@breadcrumb-bg: #f5f5f5;\n//** Breadcrumb text color\n@breadcrumb-color: #ccc;\n//** Text color of current page in the breadcrumb\n@breadcrumb-active-color: @gray-light;\n//** Textual separator for between breadcrumb elements\n@breadcrumb-separator: \"/\";\n\n\n//== Carousel\n//\n//##\n\n@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);\n\n@carousel-control-color: #fff;\n@carousel-control-width: 15%;\n@carousel-control-opacity: .5;\n@carousel-control-font-size: 20px;\n\n@carousel-indicator-active-bg: #fff;\n@carousel-indicator-border-color: #fff;\n\n@carousel-caption-color: #fff;\n\n\n//== Close\n//\n//##\n\n@close-font-weight: bold;\n@close-color: #000;\n@close-text-shadow: 0 1px 0 #fff;\n\n\n//== Code\n//\n//##\n\n@code-color: #c7254e;\n@code-bg: #f9f2f4;\n\n@kbd-color: #fff;\n@kbd-bg: #333;\n\n@pre-bg: #f5f5f5;\n@pre-color: @gray-dark;\n@pre-border-color: #ccc;\n@pre-scrollable-max-height: 340px;\n\n\n//== Type\n//\n//##\n\n//** Text muted color\n@text-muted: @gray-light;\n//** Abbreviations and acronyms border color\n@abbr-border-color: @gray-light;\n//** Headings small color\n@headings-small-color: @gray-light;\n//** Blockquote small color\n@blockquote-small-color: @gray-light;\n//** Blockquote font size\n@blockquote-font-size: (@font-size-base * 1.25);\n//** Blockquote border color\n@blockquote-border-color: @gray-lighter;\n//** Page header border color\n@page-header-border-color: @gray-lighter;\n\n\n//== Miscellaneous\n//\n//##\n\n//** Horizontal line color.\n@hr-border: @gray-lighter;\n\n//** Horizontal offset for forms and lists.\n@component-offset-horizontal: 180px;\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n display: block;\n padding: @thumbnail-padding;\n margin-bottom: @line-height-computed;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n > img,\n a > img {\n &:extend(.img-responsive);\n margin-left: auto;\n margin-right: auto;\n }\n\n // Add a hover state for linked versions only\n a&:hover,\n a&:focus,\n a&.active {\n border-color: @link-color;\n }\n\n // Image captions\n .caption {\n padding: @thumbnail-caption-padding;\n color: @thumbnail-caption-color;\n }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n position: relative;\n}\n\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n\n > .item {\n display: none;\n position: relative;\n .transition(.6s ease-in-out left);\n\n // Account for jankitude on images\n > img,\n > a > img {\n &:extend(.img-responsive);\n line-height: 1;\n }\n }\n\n > .active,\n > .next,\n > .prev { display: block; }\n\n > .active {\n left: 0;\n }\n\n > .next,\n > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n }\n\n > .next {\n left: 100%;\n }\n > .prev {\n left: -100%;\n }\n > .next.left,\n > .prev.right {\n left: 0;\n }\n\n > .active.left {\n left: -100%;\n }\n > .active.right {\n left: 100%;\n }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: @carousel-control-width;\n .opacity(@carousel-control-opacity);\n font-size: @carousel-control-font-size;\n color: @carousel-control-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n // We can't have this transition here because WebKit cancels the carousel\n // animation if you trip this while in the middle of another animation.\n\n // Set gradients for backgrounds\n &.left {\n #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n }\n &.right {\n left: auto;\n right: 0;\n #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n }\n\n // Hover/focus state\n &:hover,\n &:focus {\n outline: none;\n color: @carousel-control-color;\n text-decoration: none;\n .opacity(.9);\n }\n\n // Toggles\n .icon-prev,\n .icon-next,\n .glyphicon-chevron-left,\n .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n }\n .icon-prev,\n .glyphicon-chevron-left {\n left: 50%;\n }\n .icon-next,\n .glyphicon-chevron-right {\n right: 50%;\n }\n .icon-prev,\n .icon-next {\n width: 20px;\n height: 20px;\n margin-top: -10px;\n margin-left: -10px;\n font-family: serif;\n }\n\n .icon-prev {\n &:before {\n content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n }\n }\n .icon-next {\n &:before {\n content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n }\n }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n\n li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid @carousel-indicator-border-color;\n border-radius: 10px;\n cursor: pointer;\n\n // IE8-9 hack for event handling\n //\n // Internet Explorer 8-9 does not support clicks on elements without a set\n // `background-color`. We cannot use `filter` since that's not viewed as a\n // background color by the browser. Thus, a hack is needed.\n //\n // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n // set alpha transparency for the best results possible.\n background-color: #000 \\9; // IE8\n background-color: rgba(0,0,0,0); // IE9\n }\n .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: @carousel-indicator-active-bg;\n }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: @carousel-caption-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n & .btn {\n text-shadow: none; // No shadow for button elements in carousel-caption\n }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n // Scale up the controls a smidge\n .carousel-control {\n .glyphicon-chevron-left,\n .glyphicon-chevron-right,\n .icon-prev,\n .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n margin-left: -15px;\n font-size: 30px;\n }\n }\n\n // Show and left align the captions\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n\n // Move up the indicators\n .carousel-indicators {\n bottom: 20px;\n }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: normal;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 200;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: 14px base font * 85% = about 12px\nsmall,\n.small { font-size: 85%; }\n\n// Undo browser default styling\ncite { font-style: normal; }\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// --------------------------------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n@media (min-width: @grid-float-breakpoint) {\n .dl-horizontal {\n dt {\n float: left;\n width: (@component-offset-horizontal - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @component-offset-horizontal;\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n }\n}\n\n// MISC\n// ----\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: '\\2014 \\00A0'; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n text-align: right;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: ''; }\n &:after {\n content: '\\00A0 \\2014'; // nbsp, em dash\n }\n }\n}\n\n// Quotes\nblockquote:before,\nblockquote:after {\n content: \"\";\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n white-space: nowrap;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n word-break: break-all;\n word-wrap: break-word;\n color: @pre-color;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n max-width: 100%;\n background-color: @table-bg;\n}\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-child(odd) {\n > td,\n > th {\n background-color: @table-bg-accent;\n }\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n > td,\n > th {\n background-color: @table-bg-hover;\n }\n }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-column;\n}\ntable {\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-cell;\n }\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n@media (max-width: @screen-xs-max) {\n .table-responsive {\n width: 100%;\n margin-bottom: (@line-height-computed * 0.75);\n overflow-y: hidden;\n overflow-x: scroll;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n -webkit-overflow-scrolling: touch;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n // Chrome and Firefox set a `min-width: -webkit-min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; /* IE8-9 */\n line-height: normal;\n}\n\n// Set the height of file controls to match text inputs\ninput[type=\"file\"] {\n display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n .tab-focus();\n}\n\n// Adjust output element\noutput {\n display: block;\n padding-top: (@padding-base-vertical + 1);\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n display: block;\n width: 100%;\n height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n background-color: @input-bg;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid @input-border;\n border-radius: @input-border-radius;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n // Customize the `:focus` state to imitate native WebKit styles.\n .form-control-focus();\n\n // Placeholder\n .placeholder();\n\n // Disabled and read-only inputs\n //\n // HTML5 says that controls under a fieldset > legend:first-child won't be\n // disabled if the fieldset is disabled. Due to implementation difficulty, we\n // don't honor that edge case; we style them as disabled anyway.\n &[disabled],\n &[readonly],\n fieldset[disabled] & {\n cursor: not-allowed;\n background-color: @input-bg-disabled;\n opacity: 1; // iOS fix for unreadable disabled content\n }\n\n // Reset height for `textarea`s\n textarea& {\n height: auto;\n }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n\n\n// Special styles for iOS date input\n//\n// In Mobile Safari, date inputs require a pixel line-height that matches the\n// given height of the input.\n\ninput[type=\"date\"] {\n line-height: @input-height-base;\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n margin-bottom: 15px;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n display: block;\n min-height: @line-height-computed; // clear the floating input if there is no label text\n margin-top: 10px;\n margin-bottom: 10px;\n padding-left: 20px;\n label {\n display: inline;\n font-weight: normal;\n cursor: pointer;\n }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n float: left;\n margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"],\n.radio,\n.radio-inline,\n.checkbox,\n.checkbox-inline {\n &[disabled],\n fieldset[disabled] & {\n cursor: not-allowed;\n }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n\n.input-sm {\n .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n.input-lg {\n .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n // Enable absolute positioning\n position: relative;\n\n // Ensure icons don't overlap text\n .form-control {\n padding-right: (@input-height-base * 1.25);\n }\n\n // Feedback icon (requires .glyphicon classes)\n .form-control-feedback {\n position: absolute;\n top: (@line-height-computed + 5); // Height of the `label` and its margin\n right: 0;\n display: block;\n width: @input-height-base;\n height: @input-height-base;\n line-height: @input-height-base;\n text-align: center;\n }\n}\n\n// Feedback states\n.has-success {\n .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n margin-bottom: 0; // Remove default margin from `p`\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n display: block; // account for any element using help-block\n margin-top: 5px;\n margin-bottom: 10px;\n color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n // Kick in the inline\n @media (min-width: @screen-sm-min) {\n // Inline-block all the things for \"inline\"\n .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // In navbar-form, allow folks to *not* use `.form-group`\n .form-control {\n display: inline-block;\n width: auto; // Prevent labels from stacking above inputs in `.form-group`\n vertical-align: middle;\n }\n // Input groups need that 100% width though\n .input-group > .form-control {\n width: 100%;\n }\n\n .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // Remove default margin on radios/checkboxes that were used for stacking, and\n // then undo the floating of radios and checkboxes to match (which also avoids\n // a bug in WebKit: https://github.com/twbs/bootstrap/issues/1969).\n .radio,\n .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n padding-left: 0;\n vertical-align: middle;\n }\n .radio input[type=\"radio\"],\n .checkbox input[type=\"checkbox\"] {\n float: none;\n margin-left: 0;\n }\n\n // Validation states\n //\n // Reposition the icon because it's now within a grid column and columns have\n // `position: relative;` on them. Also accounts for the grid gutter padding.\n .has-feedback .form-control-feedback {\n top: 0;\n }\n }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n // Consistent vertical alignment of labels, radios, and checkboxes\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n }\n // Account for padding we're adding to ensure the alignment and of help text\n // and other content below items\n .radio,\n .checkbox {\n min-height: (@line-height-computed + (@padding-base-vertical + 1));\n }\n\n // Make form groups behave like rows\n .form-group {\n .make-row();\n }\n\n .form-control-static {\n padding-top: (@padding-base-vertical + 1);\n }\n\n // Only right align form labels here when the columns stop stacking\n @media (min-width: @screen-sm-min) {\n .control-label {\n text-align: right;\n }\n }\n\n // Validation states\n //\n // Reposition the icon because it's now within a grid column and columns have\n // `position: relative;` on them. Also accounts for the grid gutter padding.\n .has-feedback .form-control-feedback {\n top: 0;\n right: (@grid-gutter-width / 2);\n }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n display: inline-block;\n margin-bottom: 0; // For input.btn\n font-weight: @btn-font-weight;\n text-align: center;\n vertical-align: middle;\n cursor: pointer;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n white-space: nowrap;\n .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);\n .user-select(none);\n\n &,\n &:active,\n &.active {\n &:focus {\n .tab-focus();\n }\n }\n\n &:hover,\n &:focus {\n color: @btn-default-color;\n text-decoration: none;\n }\n\n &:active,\n &.active {\n outline: 0;\n background-image: none;\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n cursor: not-allowed;\n pointer-events: none; // Future-proof disabling of clicks\n .opacity(.65);\n .box-shadow(none);\n }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n color: @link-color;\n font-weight: normal;\n cursor: pointer;\n border-radius: 0;\n\n &,\n &:active,\n &[disabled],\n fieldset[disabled] & {\n background-color: transparent;\n .box-shadow(none);\n }\n &,\n &:hover,\n &:focus,\n &:active {\n border-color: transparent;\n }\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: underline;\n background-color: transparent;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @btn-link-disabled-color;\n text-decoration: none;\n }\n }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n // line-height: ensure even-numbered height of button next to large input\n .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n.btn-sm {\n // line-height: ensure proper height of button next to small input\n .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n.btn-xs {\n .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n display: block;\n width: 100%;\n padding-left: 0;\n padding-right: 0;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n &.btn-block {\n width: 100%;\n }\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle; // match .btn alignment given font-size hack above\n > .btn {\n position: relative;\n float: left;\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active,\n &.active {\n z-index: 2;\n }\n &:focus {\n // Remove focus outline when dropdown JS adds it after closing the menu\n outline: none;\n }\n }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n .btn + .btn,\n .btn + .btn-group,\n .btn-group + .btn,\n .btn-group + .btn-group {\n margin-left: -1px;\n }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n margin-left: -5px; // Offset the first child's margin\n &:extend(.clearfix all);\n\n .btn-group,\n .input-group {\n float: left;\n }\n > .btn,\n > .btn-group,\n > .input-group {\n margin-left: 5px;\n }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n margin-left: 0;\n &:not(:last-child):not(.dropdown-toggle) {\n .border-right-radius(0);\n }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-right-radius(0);\n }\n}\n.btn-group > .btn-group:last-child > .btn:first-child {\n .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n // Show no shadow for `.btn-link` since it has no other button styles.\n &.btn-link {\n .box-shadow(none);\n }\n}\n\n\n// Reposition the caret\n.btn .caret {\n margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n border-width: @caret-width-large @caret-width-large 0;\n border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n > .btn,\n > .btn-group,\n > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n }\n\n // Clear floats so dropdown menus can be properly placed\n > .btn-group {\n &:extend(.clearfix all);\n > .btn {\n float: none;\n }\n }\n\n > .btn + .btn,\n > .btn + .btn-group,\n > .btn-group + .btn,\n > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n }\n}\n\n.btn-group-vertical > .btn {\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n &:first-child:not(:last-child) {\n border-top-right-radius: @border-radius-base;\n .border-bottom-radius(0);\n }\n &:last-child:not(:first-child) {\n border-bottom-left-radius: @border-radius-base;\n .border-top-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-bottom-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-top-radius(0);\n}\n\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n > .btn,\n > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n }\n > .btn-group .btn {\n width: 100%;\n }\n}\n\n\n// Checkbox and radio options\n[data-toggle=\"buttons\"] > .btn > input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn > input[type=\"checkbox\"] {\n display: none;\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twitter/bootstrap/pull/3552.\n\n.fade {\n opacity: 0;\n .transition(opacity .15s linear);\n &.in {\n opacity: 1;\n }\n}\n\n.collapse {\n display: none;\n &.in {\n display: block;\n }\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n .transition(height .35s ease);\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// <a href=\"#\"><span class=\"glyphicon glyphicon-star\"></span> Star</a>\n\n// Import the fonts\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: ~\"url('@{icon-font-path}@{icon-font-name}.eot')\";\n src: ~\"url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype')\",\n ~\"url('@{icon-font-path}@{icon-font-name}.woff') format('woff')\",\n ~\"url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype')\",\n ~\"url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg')\";\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\2a\"; } }\n.glyphicon-plus { &:before { content: \"\\2b\"; } }\n.glyphicon-euro { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: @caret-width-base solid;\n border-right: @caret-width-base solid transparent;\n border-left: @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropdown {\n position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: @zindex-dropdown;\n display: none; // none by default, but block on \"open\" of the menu\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0; // override default ul\n list-style: none;\n font-size: @font-size-base;\n background-color: @dropdown-bg;\n border: 1px solid @dropdown-fallback-border; // IE8 fallback\n border: 1px solid @dropdown-border;\n border-radius: @border-radius-base;\n .box-shadow(0 6px 12px rgba(0,0,0,.175));\n background-clip: padding-box;\n\n // Aligns the dropdown menu to right\n //\n // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n &.pull-right {\n right: 0;\n left: auto;\n }\n\n // Dividers (basically an hr) within the dropdown\n .divider {\n .nav-divider(@dropdown-divider-bg);\n }\n\n // Links within the dropdown menu\n > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: @line-height-base;\n color: @dropdown-link-color;\n white-space: nowrap; // prevent links from randomly breaking onto new lines\n }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n &:hover,\n &:focus {\n text-decoration: none;\n color: @dropdown-link-hover-color;\n background-color: @dropdown-link-hover-bg;\n }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-active-color;\n text-decoration: none;\n outline: 0;\n background-color: @dropdown-link-active-bg;\n }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-disabled-color;\n }\n}\n// Nuke hover/focus effects\n.dropdown-menu > .disabled > a {\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none; // Remove CSS gradient\n .reset-filter();\n cursor: not-allowed;\n }\n}\n\n// Open state for the dropdown\n.open {\n // Show the menu\n > .dropdown-menu {\n display: block;\n }\n\n // Remove the outline when :focus is triggered\n > a {\n outline: 0;\n }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n left: auto; // Reset the default from `.dropdown-menu`\n right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: @font-size-small;\n line-height: @line-height-base;\n color: @dropdown-header-color;\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n // Reverse the caret\n .caret {\n border-top: 0;\n border-bottom: @caret-width-base solid;\n content: \"\";\n }\n // Different positioning for bottom up menu\n .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 1px;\n }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-right {\n .dropdown-menu {\n .dropdown-menu-right();\n }\n // Necessary for overrides of the default right aligned menu.\n // Will remove come v4 in all likelihood.\n .dropdown-menu-left {\n .dropdown-menu-left();\n }\n }\n}\n\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n position: relative; // For dropdowns\n display: table;\n border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n // Undo padding and float of grid classes\n &[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n }\n\n .form-control {\n // Ensure that the input is always above the *appended* addon button for\n // proper border colors.\n position: relative;\n z-index: 2;\n\n // IE9 fubars the placeholder attribute in text inputs and the arrows on\n // select elements in input groups. To fix it, we float the input. Details:\n // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n float: left;\n\n width: 100%;\n margin-bottom: 0;\n }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn { .input-lg(); }\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn { .input-sm(); }\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: 1;\n color: @input-color;\n text-align: center;\n background-color: @input-group-addon-bg;\n border: 1px solid @input-group-addon-border-color;\n border-radius: @border-radius-base;\n\n // Sizing\n &.input-sm {\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n border-radius: @border-radius-small;\n }\n &.input-lg {\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n border-radius: @border-radius-large;\n }\n\n // Nuke default margins from checkboxes and radios to vertically center within.\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n margin-top: 0;\n }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n .border-right-radius(0);\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n .border-left-radius(0);\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n position: relative;\n // Jankily prevent input button groups from wrapping with `white-space` and\n // `font-size` in combination with `inline-block` on buttons.\n font-size: 0;\n white-space: nowrap;\n\n // Negative margin for spacing, position for bringing hovered/focused/actived\n // element above the siblings.\n > .btn {\n position: relative;\n + .btn {\n margin-left: -1px;\n }\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active {\n z-index: 2;\n }\n }\n\n // Negative margin to only have a 1px border between the two\n &:first-child {\n > .btn,\n > .btn-group {\n margin-right: -1px;\n }\n }\n &:last-child {\n > .btn,\n > .btn-group {\n margin-left: -1px;\n }\n }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n margin-bottom: 0;\n padding-left: 0; // Override default ul/ol\n list-style: none;\n &:extend(.clearfix all);\n\n > li {\n position: relative;\n display: block;\n\n > a {\n position: relative;\n display: block;\n padding: @nav-link-padding;\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @nav-link-hover-bg;\n }\n }\n\n // Disabled state sets text to gray and nukes hover/tab effects\n &.disabled > a {\n color: @nav-disabled-link-color;\n\n &:hover,\n &:focus {\n color: @nav-disabled-link-hover-color;\n text-decoration: none;\n background-color: transparent;\n cursor: not-allowed;\n }\n }\n }\n\n // Open dropdowns\n .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @nav-link-hover-bg;\n border-color: @link-color;\n }\n }\n\n // Nav dividers (deprecated with v3.0.1)\n //\n // This should have been removed in v3 with the dropping of `.nav-list`, but\n // we missed it. We don't currently support this anywhere, but in the interest\n // of maintaining backward compatibility in case you use it, it's deprecated.\n .nav-divider {\n .nav-divider();\n }\n\n // Prevent IE8 from misplacing imgs\n //\n // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n > li > a > img {\n max-width: none;\n }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n border-bottom: 1px solid @nav-tabs-border-color;\n > li {\n float: left;\n // Make the list-items overlay the bottom border\n margin-bottom: -1px;\n\n // Actual tabs (as links)\n > a {\n margin-right: 2px;\n line-height: @line-height-base;\n border: 1px solid transparent;\n border-radius: @border-radius-base @border-radius-base 0 0;\n &:hover {\n border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n }\n }\n\n // Active state, and its :hover to override normal :hover\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-tabs-active-link-hover-color;\n background-color: @nav-tabs-active-link-hover-bg;\n border: 1px solid @nav-tabs-active-link-hover-border-color;\n border-bottom-color: transparent;\n cursor: default;\n }\n }\n }\n // pulling this in mainly for less shorthand\n &.nav-justified {\n .nav-justified();\n .nav-tabs-justified();\n }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n > li {\n float: left;\n\n // Links rendered as pills\n > a {\n border-radius: @nav-pills-border-radius;\n }\n + li {\n margin-left: 2px;\n }\n\n // Active state\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-pills-active-link-hover-color;\n background-color: @nav-pills-active-link-hover-bg;\n }\n }\n }\n}\n\n\n// Stacked pills\n.nav-stacked {\n > li {\n float: none;\n + li {\n margin-top: 2px;\n margin-left: 0; // no need for this gap between nav items\n }\n }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n width: 100%;\n\n > li {\n float: none;\n > a {\n text-align: center;\n margin-bottom: 5px;\n }\n }\n\n > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n }\n\n @media (min-width: @screen-sm-min) {\n > li {\n display: table-cell;\n width: 1%;\n > a {\n margin-bottom: 0;\n }\n }\n }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n border-bottom: 0;\n\n > li > a {\n // Override margin from .nav-tabs\n margin-right: 0;\n border-radius: @border-radius-base;\n }\n\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border: 1px solid @nav-tabs-justified-link-border-color;\n }\n\n @media (min-width: @screen-sm-min) {\n > li > a {\n border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n border-radius: @border-radius-base @border-radius-base 0 0;\n }\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border-bottom-color: @nav-tabs-justified-active-link-border-color;\n }\n }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n > .tab-pane {\n display: none;\n }\n > .active {\n display: block;\n }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n // make dropdown border overlap tab border\n margin-top: -1px;\n // Remove the top rounded corners here since there is a hard edge above the menu\n .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n position: relative;\n min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n margin-bottom: @navbar-margin-bottom;\n border: 1px solid transparent;\n\n // Prevent floats from breaking the navbar\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: @navbar-border-radius;\n }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n max-height: @navbar-collapse-max-height;\n overflow-x: visible;\n padding-right: @navbar-padding-horizontal;\n padding-left: @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n &:extend(.clearfix all);\n -webkit-overflow-scrolling: touch;\n\n &.in {\n overflow-y: auto;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border-top: 0;\n box-shadow: none;\n\n &.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0; // Override default setting\n overflow: visible !important;\n }\n\n &.in {\n overflow-y: visible;\n }\n\n // Undo the collapse side padding for navbars with containers to ensure\n // alignment of right-aligned contents.\n .navbar-fixed-top &,\n .navbar-static-top &,\n .navbar-fixed-bottom & {\n padding-left: 0;\n padding-right: 0;\n }\n }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n > .navbar-header,\n > .navbar-collapse {\n margin-right: -@navbar-padding-horizontal;\n margin-left: -@navbar-padding-horizontal;\n\n @media (min-width: @grid-float-breakpoint) {\n margin-right: 0;\n margin-left: 0;\n }\n }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n z-index: @zindex-navbar;\n border-width: 0 0 1px;\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: @zindex-navbar-fixed;\n\n // Undo the rounded corners\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0; // override .navbar defaults\n border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n float: left;\n padding: @navbar-padding-vertical @navbar-padding-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-computed;\n height: @navbar-height;\n\n &:hover,\n &:focus {\n text-decoration: none;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n .navbar > .container &,\n .navbar > .container-fluid & {\n margin-left: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: @navbar-padding-horizontal;\n padding: 9px 10px;\n .navbar-vertical-align(34px);\n background-color: transparent;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n border-radius: @border-radius-base;\n\n // We remove the `outline` here, but later compensate by attaching `:hover`\n // styles to `:focus`.\n &:focus {\n outline: none;\n }\n\n // Bars\n .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n }\n .icon-bar + .icon-bar {\n margin-top: 4px;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n display: none;\n }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: @line-height-computed;\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n > li > a,\n .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n > li > a {\n line-height: @line-height-computed;\n &:hover,\n &:focus {\n background-image: none;\n }\n }\n }\n }\n\n // Uncollapse the nav\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin: 0;\n\n > li {\n float: left;\n > a {\n padding-top: @navbar-padding-vertical;\n padding-bottom: @navbar-padding-vertical;\n }\n }\n\n &.navbar-right:last-child {\n margin-right: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-left { .pull-left(); }\n .navbar-right { .pull-right(); }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n margin-left: -@navbar-padding-horizontal;\n margin-right: -@navbar-padding-horizontal;\n padding: 10px @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n\n // Mixin behavior for optimum display\n .form-inline();\n\n .form-group {\n @media (max-width: @grid-float-breakpoint-max) {\n margin-bottom: 5px;\n }\n }\n\n // Vertically center in expanded, horizontal navbar\n .navbar-vertical-align(@input-height-base);\n\n // Undo 100% width for pull classes\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n .box-shadow(none);\n\n // Outdent the form if last child to line up with content down the page\n &.navbar-right:last-child {\n margin-right: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n .navbar-vertical-align(@input-height-base);\n\n &.btn-sm {\n .navbar-vertical-align(@input-height-small);\n }\n &.btn-xs {\n .navbar-vertical-align(22);\n }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n .navbar-vertical-align(@line-height-computed);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin-left: @navbar-padding-horizontal;\n margin-right: @navbar-padding-horizontal;\n\n // Outdent the form if last child to line up with content down the page\n &.navbar-right:last-child {\n margin-right: 0;\n }\n }\n}\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n background-color: @navbar-default-bg;\n border-color: @navbar-default-border;\n\n .navbar-brand {\n color: @navbar-default-brand-color;\n &:hover,\n &:focus {\n color: @navbar-default-brand-hover-color;\n background-color: @navbar-default-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-default-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-default-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n\n .navbar-toggle {\n border-color: @navbar-default-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-default-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-default-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: @navbar-default-border;\n }\n\n // Dropdown menu items\n .navbar-nav {\n // Remove background color from open dropdown\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-default-link-active-bg;\n color: @navbar-default-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n > li > a {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n }\n }\n\n\n // Links in navbars\n //\n // Add a class to ensure links outside the navbar nav are colored correctly.\n\n .navbar-link {\n color: @navbar-default-link-color;\n &:hover {\n color: @navbar-default-link-hover-color;\n }\n }\n\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n background-color: @navbar-inverse-bg;\n border-color: @navbar-inverse-border;\n\n .navbar-brand {\n color: @navbar-inverse-brand-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-brand-hover-color;\n background-color: @navbar-inverse-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-inverse-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-inverse-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n\n // Darken the responsive nav toggle\n .navbar-toggle {\n border-color: @navbar-inverse-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-inverse-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-inverse-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: darken(@navbar-inverse-bg, 7%);\n }\n\n // Dropdowns\n .navbar-nav {\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-inverse-link-active-bg;\n color: @navbar-inverse-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display\n .open .dropdown-menu {\n > .dropdown-header {\n border-color: @navbar-inverse-border;\n }\n .divider {\n background-color: @navbar-inverse-border;\n }\n > li > a {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n }\n }\n\n .navbar-link {\n color: @navbar-inverse-link-color;\n &:hover {\n color: @navbar-inverse-link-hover-color;\n }\n }\n\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n .clearfix();\n}\n.center-block {\n .center-block();\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n display: none !important;\n visibility: hidden !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n margin-bottom: @line-height-computed;\n list-style: none;\n background-color: @breadcrumb-bg;\n border-radius: @border-radius-base;\n\n > li {\n display: inline-block;\n\n + li:before {\n content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n padding: 0 5px;\n color: @breadcrumb-color;\n }\n }\n\n > .active {\n color: @breadcrumb-active-color;\n }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: @line-height-computed 0;\n border-radius: @border-radius-base;\n\n > li {\n display: inline; // Remove list-style and block-level defaults\n > a,\n > span {\n position: relative;\n float: left; // Collapse white-space\n padding: @padding-base-vertical @padding-base-horizontal;\n line-height: @line-height-base;\n text-decoration: none;\n color: @pagination-color;\n background-color: @pagination-bg;\n border: 1px solid @pagination-border;\n margin-left: -1px;\n }\n &:first-child {\n > a,\n > span {\n margin-left: 0;\n .border-left-radius(@border-radius-base);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius-base);\n }\n }\n }\n\n > li > a,\n > li > span {\n &:hover,\n &:focus {\n color: @pagination-hover-color;\n background-color: @pagination-hover-bg;\n border-color: @pagination-hover-border;\n }\n }\n\n > .active > a,\n > .active > span {\n &,\n &:hover,\n &:focus {\n z-index: 2;\n color: @pagination-active-color;\n background-color: @pagination-active-bg;\n border-color: @pagination-active-border;\n cursor: default;\n }\n }\n\n > .disabled {\n > span,\n > span:hover,\n > span:focus,\n > a,\n > a:hover,\n > a:focus {\n color: @pagination-disabled-color;\n background-color: @pagination-disabled-bg;\n border-color: @pagination-disabled-border;\n cursor: not-allowed;\n }\n }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n padding-left: 0;\n margin: @line-height-computed 0;\n list-style: none;\n text-align: center;\n &:extend(.clearfix all);\n li {\n display: inline;\n > a,\n > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: @pager-bg;\n border: 1px solid @pager-border;\n border-radius: @pager-border-radius;\n }\n\n > a:hover,\n > a:focus {\n text-decoration: none;\n background-color: @pager-hover-bg;\n }\n }\n\n .next {\n > a,\n > span {\n float: right;\n }\n }\n\n .previous {\n > a,\n > span {\n float: left;\n }\n }\n\n .disabled {\n > a,\n > a:hover,\n > a:focus,\n > span {\n color: @pager-disabled-color;\n background-color: @pager-bg;\n cursor: not-allowed;\n }\n }\n\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: @label-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n\n // Add hover effects, but only for links\n &[href] {\n &:hover,\n &:focus {\n color: @label-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Empty labels collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for labels in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n .label-variant(@label-default-bg);\n}\n\n.label-primary {\n .label-variant(@label-primary-bg);\n}\n\n.label-success {\n .label-variant(@label-success-bg);\n}\n\n.label-info {\n .label-variant(@label-info-bg);\n}\n\n.label-warning {\n .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n .label-variant(@label-danger-bg);\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base classes\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: @font-size-small;\n font-weight: @badge-font-weight;\n color: @badge-color;\n line-height: @badge-line-height;\n vertical-align: baseline;\n white-space: nowrap;\n text-align: center;\n background-color: @badge-bg;\n border-radius: @badge-border-radius;\n\n // Empty badges collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for badges in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n .btn-xs & {\n top: 0;\n padding: 1px 5px;\n }\n}\n\n// Hover state, but only for links\na.badge {\n &:hover,\n &:focus {\n color: @badge-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n}\n\n// Account for counters in navs\na.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: @badge-active-color;\n background-color: @badge-active-bg;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n padding: @jumbotron-padding;\n margin-bottom: @jumbotron-padding;\n color: @jumbotron-color;\n background-color: @jumbotron-bg;\n\n h1,\n .h1 {\n color: @jumbotron-heading-color;\n }\n p {\n margin-bottom: (@jumbotron-padding / 2);\n font-size: @jumbotron-font-size;\n font-weight: 200;\n }\n\n .container & {\n border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n }\n\n .container {\n max-width: 100%;\n }\n\n @media screen and (min-width: @screen-sm-min) {\n padding-top: (@jumbotron-padding * 1.6);\n padding-bottom: (@jumbotron-padding * 1.6);\n\n .container & {\n padding-left: (@jumbotron-padding * 2);\n padding-right: (@jumbotron-padding * 2);\n }\n\n h1,\n .h1 {\n font-size: (@font-size-base * 4.5);\n }\n }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n padding: @alert-padding;\n margin-bottom: @line-height-computed;\n border: 1px solid transparent;\n border-radius: @alert-border-radius;\n\n // Headings for larger alerts\n h4 {\n margin-top: 0;\n // Specified for the h4 to prevent conflicts of changing @headings-color\n color: inherit;\n }\n // Provide class for links that match alerts\n .alert-link {\n font-weight: @alert-link-font-weight;\n }\n\n // Improve alignment and spacing of inner content\n > p,\n > ul {\n margin-bottom: 0;\n }\n > p + p {\n margin-top: 5px;\n }\n}\n\n// Dismissable alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable {\n padding-right: (@alert-padding + 20);\n\n // Adjust close link position\n .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n.alert-info {\n .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n.alert-warning {\n .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n.alert-danger {\n .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n overflow: hidden;\n height: @line-height-computed;\n margin-bottom: @line-height-computed;\n background-color: @progress-bg;\n border-radius: @border-radius-base;\n .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: @font-size-small;\n line-height: @line-height-computed;\n color: @progress-bar-color;\n text-align: center;\n background-color: @progress-bar-bg;\n .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n .transition(width .6s ease);\n}\n\n// Striped bars\n.progress-striped .progress-bar {\n #gradient > .striped();\n background-size: 40px 40px;\n}\n\n// Call animation for the active one\n.progress.active .progress-bar {\n .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Media objects\n// Source: http://stubbornella.org/content/?p=497\n// --------------------------------------------------\n\n\n// Common styles\n// -------------------------\n\n// Clear the floats\n.media,\n.media-body {\n overflow: hidden;\n zoom: 1;\n}\n\n// Proper spacing between instances of .media\n.media,\n.media .media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n\n// For images and videos, set to block\n.media-object {\n display: block;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n margin: 0 0 5px;\n}\n\n\n// Media image alignment\n// -------------------------\n\n.media {\n > .pull-left {\n margin-right: 10px;\n }\n > .pull-right {\n margin-left: 10px;\n }\n}\n\n\n// Media list variation\n// -------------------------\n\n// Undo default ul/ol styles\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on <ul>, <ol>, or <div>.\n\n.list-group {\n // No need to set list-style: none; since .list-group-item is block level\n margin-bottom: 20px;\n padding-left: 0; // reset padding because ul and ol\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n // Place the border on the list items and negative margin up for better styling\n margin-bottom: -1px;\n background-color: @list-group-bg;\n border: 1px solid @list-group-border;\n\n // Round the first and last items\n &:first-child {\n .border-top-radius(@list-group-border-radius);\n }\n &:last-child {\n margin-bottom: 0;\n .border-bottom-radius(@list-group-border-radius);\n }\n\n // Align badges within list items\n > .badge {\n float: right;\n }\n > .badge + .badge {\n margin-right: 5px;\n }\n}\n\n\n// Linked list items\n//\n// Use anchor elements instead of `li`s or `div`s to create linked list items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item {\n color: @list-group-link-color;\n\n .list-group-item-heading {\n color: @list-group-link-heading-color;\n }\n\n // Hover state\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @list-group-hover-bg;\n }\n\n // Active class on item itself, not parent\n &.active,\n &.active:hover,\n &.active:focus {\n z-index: 2; // Place active items above their siblings for proper border styling\n color: @list-group-active-color;\n background-color: @list-group-active-bg;\n border-color: @list-group-active-border;\n\n // Force color to inherit for custom content\n .list-group-item-heading {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-active-text-color;\n }\n }\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\n\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n","//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n margin-bottom: @line-height-computed;\n background-color: @panel-bg;\n border: 1px solid transparent;\n border-radius: @panel-border-radius;\n .box-shadow(0 1px 1px rgba(0,0,0,.05));\n}\n\n// Panel contents\n.panel-body {\n padding: @panel-body-padding;\n &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n .border-top-radius((@panel-border-radius - 1));\n\n > .dropdown .dropdown-toggle {\n color: inherit;\n }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: ceil((@font-size-base * 1.125));\n color: inherit;\n\n > a {\n color: inherit;\n }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n padding: 10px 15px;\n background-color: @panel-footer-bg;\n border-top: 1px solid @panel-inner-border;\n .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n > .list-group {\n margin-bottom: 0;\n\n .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n }\n\n // Add border top radius for first one\n &:first-child {\n .list-group-item:first-child {\n border-top: 0;\n .border-top-radius((@panel-border-radius - 1));\n }\n }\n // Add border bottom radius for last one\n &:last-child {\n .list-group-item:last-child {\n border-bottom: 0;\n .border-bottom-radius((@panel-border-radius - 1));\n }\n }\n }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n .list-group-item:first-child {\n border-top-width: 0;\n }\n}\n\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n > .table,\n > .table-responsive > .table {\n margin-bottom: 0;\n }\n // Add border top radius for first one\n > .table:first-child,\n > .table-responsive:first-child > .table:first-child {\n .border-top-radius((@panel-border-radius - 1));\n\n > thead:first-child,\n > tbody:first-child {\n > tr:first-child {\n td:first-child,\n th:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-top-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n // Add border bottom radius for last one\n > .table:last-child,\n > .table-responsive:last-child > .table:last-child {\n .border-bottom-radius((@panel-border-radius - 1));\n\n > tbody:last-child,\n > tfoot:last-child {\n > tr:last-child {\n td:first-child,\n th:first-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-bottom-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n > .panel-body + .table,\n > .panel-body + .table-responsive {\n border-top: 1px solid @table-border-color;\n }\n > .table > tbody:first-child > tr:first-child th,\n > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n }\n > .table-bordered,\n > .table-responsive > .table-bordered {\n border: 0;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n > thead,\n > tbody {\n > tr:first-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n > tbody,\n > tfoot {\n > tr:last-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n }\n > .table-responsive {\n border: 0;\n margin-bottom: 0;\n }\n}\n\n\n// Collapsable panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n margin-bottom: @line-height-computed;\n\n // Tighten up margin so it's only between panels\n .panel {\n margin-bottom: 0;\n border-radius: @panel-border-radius;\n overflow: hidden; // crop contents when collapsed\n + .panel {\n margin-top: 5px;\n }\n }\n\n .panel-heading {\n border-bottom: 0;\n + .panel-collapse .panel-body {\n border-top: 1px solid @panel-inner-border;\n }\n }\n .panel-footer {\n border-top: 0;\n + .panel-collapse .panel-body {\n border-bottom: 1px solid @panel-inner-border;\n }\n }\n}\n\n\n// Contextual variations\n.panel-default {\n .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n","//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: @well-bg;\n border: 1px solid @well-border;\n border-radius: @border-radius-base;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));\n blockquote {\n border-color: #ddd;\n border-color: rgba(0,0,0,.15);\n }\n}\n\n// Sizes\n.well-lg {\n padding: 24px;\n border-radius: @border-radius-large;\n}\n.well-sm {\n padding: 9px;\n border-radius: @border-radius-small;\n}\n","//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n float: right;\n font-size: (@font-size-base * 1.5);\n font-weight: @close-font-weight;\n line-height: 1;\n color: @close-color;\n text-shadow: @close-text-shadow;\n .opacity(.2);\n\n &:hover,\n &:focus {\n color: @close-color;\n text-decoration: none;\n cursor: pointer;\n .opacity(.5);\n }\n\n // Additional properties for button version\n // iOS requires the button element instead of an anchor tag.\n // If you want the anchor version, it requires `href=\"#\"`.\n button& {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n }\n}\n","//\n// Modals\n// --------------------------------------------------\n\n// .modal-open - body class for killing the scroll\n// .modal - container to scroll within\n// .modal-dialog - positioning shell for the actual modal\n// .modal-content - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n display: none;\n overflow: auto;\n overflow-y: scroll;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal;\n -webkit-overflow-scrolling: touch;\n\n // Prevent Chrome on Windows from adding a focus outline. For details, see\n // https://github.com/twbs/bootstrap/pull/10951.\n outline: 0;\n\n // When fading in the modal, animate it to slide down\n &.fade .modal-dialog {\n .translate(0, -25%);\n .transition-transform(~\"0.3s ease-out\");\n }\n &.in .modal-dialog { .translate(0, 0)}\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n position: relative;\n background-color: @modal-content-bg;\n border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n border: 1px solid @modal-content-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 3px 9px rgba(0,0,0,.5));\n background-clip: padding-box;\n // Remove focus outline from opened modal\n outline: none;\n}\n\n// Modal background\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal-background;\n background-color: @modal-backdrop-bg;\n // Fade for backdrop\n &.fade { .opacity(0); }\n &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n padding: @modal-title-padding;\n border-bottom: 1px solid @modal-header-border-color;\n min-height: (@modal-title-padding + @modal-title-line-height);\n}\n// Close icon\n.modal-header .close {\n margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n margin: 0;\n line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n position: relative;\n padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n margin-top: 15px;\n padding: (@modal-inner-padding - 1) @modal-inner-padding @modal-inner-padding;\n text-align: right; // right align buttons\n border-top: 1px solid @modal-footer-border-color;\n &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n // Properly space out buttons\n .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n }\n // but override that for button groups\n .btn-group .btn + .btn {\n margin-left: -1px;\n }\n // and override it for block buttons as well\n .btn-block + .btn-block {\n margin-left: 0;\n }\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n // Automatically set modal's width for larger viewports\n .modal-dialog {\n width: @modal-md;\n margin: 30px auto;\n }\n .modal-content {\n .box-shadow(0 5px 15px rgba(0,0,0,.5));\n }\n\n // Modal sizes\n .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n .modal-lg { width: @modal-lg; }\n}\n","//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n position: absolute;\n z-index: @zindex-tooltip;\n display: block;\n visibility: visible;\n font-size: @font-size-small;\n line-height: 1.4;\n .opacity(0);\n\n &.in { .opacity(@tooltip-opacity); }\n &.top { margin-top: -3px; padding: @tooltip-arrow-width 0; }\n &.right { margin-left: 3px; padding: 0 @tooltip-arrow-width; }\n &.bottom { margin-top: 3px; padding: @tooltip-arrow-width 0; }\n &.left { margin-left: -3px; padding: 0 @tooltip-arrow-width; }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n max-width: @tooltip-max-width;\n padding: 3px 8px;\n color: @tooltip-color;\n text-align: center;\n text-decoration: none;\n background-color: @tooltip-bg;\n border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.tooltip {\n &.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-left .tooltip-arrow {\n bottom: 0;\n left: @tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-right .tooltip-arrow {\n bottom: 0;\n right: @tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n border-right-color: @tooltip-arrow-color;\n }\n &.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-left-color: @tooltip-arrow-color;\n }\n &.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-left .tooltip-arrow {\n top: 0;\n left: @tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-right .tooltip-arrow {\n top: 0;\n right: @tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n}\n","//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: @zindex-popover;\n display: none;\n max-width: @popover-max-width;\n padding: 1px;\n text-align: left; // Reset given new insertion method\n background-color: @popover-bg;\n background-clip: padding-box;\n border: 1px solid @popover-fallback-border-color;\n border: 1px solid @popover-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 5px 10px rgba(0,0,0,.2));\n\n // Overrides for proper insertion\n white-space: normal;\n\n // Offset the popover to account for the popover arrow\n &.top { margin-top: -@popover-arrow-width; }\n &.right { margin-left: @popover-arrow-width; }\n &.bottom { margin-top: @popover-arrow-width; }\n &.left { margin-left: -@popover-arrow-width; }\n}\n\n.popover-title {\n margin: 0; // reset heading margin\n padding: 8px 14px;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: 18px;\n background-color: @popover-title-bg;\n border-bottom: 1px solid darken(@popover-title-bg, 5%);\n border-radius: 5px 5px 0 0;\n}\n\n.popover-content {\n padding: 9px 14px;\n}\n\n// Arrows\n//\n// .arrow is outer, .arrow:after is inner\n\n.popover > .arrow {\n &,\n &:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n }\n}\n.popover > .arrow {\n border-width: @popover-arrow-outer-width;\n}\n.popover > .arrow:after {\n border-width: @popover-arrow-width;\n content: \"\";\n}\n\n.popover {\n &.top > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-top-color: @popover-arrow-outer-color;\n bottom: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n bottom: 1px;\n margin-left: -@popover-arrow-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-color;\n }\n }\n &.right > .arrow {\n top: 50%;\n left: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-right-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n left: 1px;\n bottom: -@popover-arrow-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-color;\n }\n }\n &.bottom > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-bottom-color: @popover-arrow-outer-color;\n top: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n top: 1px;\n margin-left: -@popover-arrow-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-color;\n }\n }\n\n &.left > .arrow {\n top: 50%;\n right: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-right-width: 0;\n border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-left-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: @popover-arrow-color;\n bottom: -@popover-arrow-width;\n }\n }\n\n}\n","//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: http://getbootstrap.com/getting-started/#browsers\n// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n width: device-width;\n}\n\n\n// Visibility utilities\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n .responsive-invisibility();\n}\n\n.visible-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-visibility();\n }\n}\n.visible-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-visibility();\n }\n}\n.visible-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-visibility();\n }\n}\n.visible-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-visibility();\n }\n}\n\n.hidden-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-invisibility();\n }\n}\n.hidden-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-invisibility();\n }\n}\n.hidden-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-invisibility();\n }\n}\n.hidden-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-invisibility();\n }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n.visible-print {\n .responsive-invisibility();\n\n @media print {\n .responsive-visibility();\n }\n}\n\n.hidden-print {\n @media print {\n .responsive-invisibility();\n }\n}\n"]} \ No newline at end of file
diff --git a/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot b/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000..4a4ca86
--- /dev/null
+++ b/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg b/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000..e3e2dc7
--- /dev/null
+++ b/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,229 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph />
+<glyph />
+<glyph unicode="&#xd;" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
+<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#x2000;" horiz-adv-x="652" />
+<glyph unicode="&#x2001;" horiz-adv-x="1304" />
+<glyph unicode="&#x2002;" horiz-adv-x="652" />
+<glyph unicode="&#x2003;" horiz-adv-x="1304" />
+<glyph unicode="&#x2004;" horiz-adv-x="434" />
+<glyph unicode="&#x2005;" horiz-adv-x="326" />
+<glyph unicode="&#x2006;" horiz-adv-x="217" />
+<glyph unicode="&#x2007;" horiz-adv-x="217" />
+<glyph unicode="&#x2008;" horiz-adv-x="163" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="326" />
+<glyph unicode="&#x20ac;" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
+<glyph unicode="&#x2212;" d="M200 400h900v300h-900v-300z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
+<glyph unicode="&#x2709;" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
+<glyph unicode="&#x270f;" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
+<glyph unicode="&#xe001;" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
+<glyph unicode="&#xe002;" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
+<glyph unicode="&#xe003;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
+<glyph unicode="&#xe005;" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
+<glyph unicode="&#xe006;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
+<glyph unicode="&#xe007;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
+<glyph unicode="&#xe008;" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
+<glyph unicode="&#xe009;" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
+<glyph unicode="&#xe010;" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe011;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe012;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe013;" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
+<glyph unicode="&#xe014;" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
+<glyph unicode="&#xe015;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
+<glyph unicode="&#xe016;" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
+<glyph unicode="&#xe017;" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
+<glyph unicode="&#xe018;" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
+<glyph unicode="&#xe019;" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
+<glyph unicode="&#xe020;" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
+<glyph unicode="&#xe021;" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
+<glyph unicode="&#xe022;" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
+<glyph unicode="&#xe023;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
+<glyph unicode="&#xe024;" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
+<glyph unicode="&#xe026;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
+<glyph unicode="&#xe027;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
+<glyph unicode="&#xe028;" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
+<glyph unicode="&#xe029;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
+<glyph unicode="&#xe030;" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
+<glyph unicode="&#xe031;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
+<glyph unicode="&#xe032;" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
+<glyph unicode="&#xe033;" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
+<glyph unicode="&#xe034;" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
+<glyph unicode="&#xe035;" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
+<glyph unicode="&#xe036;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
+<glyph unicode="&#xe037;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
+<glyph unicode="&#xe038;" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
+<glyph unicode="&#xe039;" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
+<glyph unicode="&#xe040;" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
+<glyph unicode="&#xe041;" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
+<glyph unicode="&#xe042;" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
+<glyph unicode="&#xe043;" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
+<glyph unicode="&#xe044;" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
+<glyph unicode="&#xe045;" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
+<glyph unicode="&#xe046;" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
+<glyph unicode="&#xe047;" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
+<glyph unicode="&#xe048;" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
+<glyph unicode="&#xe049;" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
+<glyph unicode="&#xe050;" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
+<glyph unicode="&#xe051;" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
+<glyph unicode="&#xe052;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe053;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe054;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe055;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe056;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe057;" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe058;" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
+<glyph unicode="&#xe059;" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
+<glyph unicode="&#xe062;" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
+<glyph unicode="&#xe063;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
+<glyph unicode="&#xe064;" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
+<glyph unicode="&#xe065;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
+<glyph unicode="&#xe066;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
+<glyph unicode="&#xe067;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
+<glyph unicode="&#xe068;" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
+<glyph unicode="&#xe069;" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe070;" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe071;" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
+<glyph unicode="&#xe072;" d="M200 0l900 550l-900 550v-1100z" />
+<glyph unicode="&#xe073;" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe074;" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe075;" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
+<glyph unicode="&#xe076;" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
+<glyph unicode="&#xe077;" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
+<glyph unicode="&#xe078;" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
+<glyph unicode="&#xe079;" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
+<glyph unicode="&#xe080;" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
+<glyph unicode="&#xe081;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
+<glyph unicode="&#xe082;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
+<glyph unicode="&#xe083;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
+<glyph unicode="&#xe084;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
+<glyph unicode="&#xe085;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
+<glyph unicode="&#xe086;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
+<glyph unicode="&#xe087;" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
+<glyph unicode="&#xe088;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
+<glyph unicode="&#xe089;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
+<glyph unicode="&#xe090;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
+<glyph unicode="&#xe091;" d="M0 547l600 453v-300h600v-300h-600v-301z" />
+<glyph unicode="&#xe092;" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
+<glyph unicode="&#xe093;" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
+<glyph unicode="&#xe094;" d="M104 600h296v600h300v-600h298l-449 -600z" />
+<glyph unicode="&#xe095;" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
+<glyph unicode="&#xe096;" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
+<glyph unicode="&#xe097;" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
+<glyph unicode="&#xe101;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
+<glyph unicode="&#xe102;" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
+<glyph unicode="&#xe103;" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
+<glyph unicode="&#xe104;" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
+<glyph unicode="&#xe105;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
+<glyph unicode="&#xe106;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
+<glyph unicode="&#xe107;" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
+<glyph unicode="&#xe108;" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
+<glyph unicode="&#xe109;" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
+<glyph unicode="&#xe110;" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
+<glyph unicode="&#xe111;" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
+<glyph unicode="&#xe112;" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
+<glyph unicode="&#xe113;" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
+<glyph unicode="&#xe114;" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
+<glyph unicode="&#xe115;" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
+<glyph unicode="&#xe116;" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
+<glyph unicode="&#xe117;" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
+<glyph unicode="&#xe118;" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
+<glyph unicode="&#xe119;" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
+<glyph unicode="&#xe120;" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
+<glyph unicode="&#xe121;" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
+<glyph unicode="&#xe122;" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe123;" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
+<glyph unicode="&#xe124;" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
+<glyph unicode="&#xe125;" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
+<glyph unicode="&#xe126;" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
+<glyph unicode="&#xe127;" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
+<glyph unicode="&#xe128;" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
+<glyph unicode="&#xe129;" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
+<glyph unicode="&#xe130;" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
+<glyph unicode="&#xe131;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
+<glyph unicode="&#xe132;" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
+<glyph unicode="&#xe133;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
+<glyph unicode="&#xe134;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
+<glyph unicode="&#xe135;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
+<glyph unicode="&#xe136;" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
+<glyph unicode="&#xe138;" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
+<glyph unicode="&#xe139;" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
+<glyph unicode="&#xe140;" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
+<glyph unicode="&#xe141;" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
+<glyph unicode="&#xe142;" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
+<glyph unicode="&#xe143;" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
+<glyph unicode="&#xe144;" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
+<glyph unicode="&#xe145;" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
+<glyph unicode="&#xe146;" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
+<glyph unicode="&#xe148;" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
+<glyph unicode="&#xe149;" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
+<glyph unicode="&#xe150;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
+<glyph unicode="&#xe151;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
+<glyph unicode="&#xe152;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
+<glyph unicode="&#xe153;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
+<glyph unicode="&#xe154;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
+<glyph unicode="&#xe155;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
+<glyph unicode="&#xe156;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
+<glyph unicode="&#xe157;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
+<glyph unicode="&#xe158;" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
+<glyph unicode="&#xe159;" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
+<glyph unicode="&#xe160;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
+<glyph unicode="&#xe161;" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
+<glyph unicode="&#xe162;" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
+<glyph unicode="&#xe163;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
+<glyph unicode="&#xe164;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
+<glyph unicode="&#xe165;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
+<glyph unicode="&#xe166;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe167;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe168;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe169;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe170;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe171;" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
+<glyph unicode="&#xe172;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe173;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe174;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
+<glyph unicode="&#xe175;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe176;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe177;" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
+<glyph unicode="&#xe178;" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
+<glyph unicode="&#xe179;" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
+<glyph unicode="&#xe180;" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
+<glyph unicode="&#xe181;" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
+<glyph unicode="&#xe182;" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
+<glyph unicode="&#xe183;" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
+<glyph unicode="&#xe184;" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
+<glyph unicode="&#xe185;" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
+<glyph unicode="&#xe186;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe187;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe188;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
+<glyph unicode="&#xe189;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
+<glyph unicode="&#xe190;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
+<glyph unicode="&#xe191;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe192;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe193;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
+<glyph unicode="&#xe194;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
+<glyph unicode="&#xe195;" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
+<glyph unicode="&#xe197;" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
+<glyph unicode="&#xe198;" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
+<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
+<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf b/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000..67fa00b
--- /dev/null
+++ b/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff b/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000..8c54182
--- /dev/null
+++ b/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot b/bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000..4a4ca86
--- /dev/null
+++ b/bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg b/bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000..e3e2dc7
--- /dev/null
+++ b/bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,229 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph />
+<glyph />
+<glyph unicode="&#xd;" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
+<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#x2000;" horiz-adv-x="652" />
+<glyph unicode="&#x2001;" horiz-adv-x="1304" />
+<glyph unicode="&#x2002;" horiz-adv-x="652" />
+<glyph unicode="&#x2003;" horiz-adv-x="1304" />
+<glyph unicode="&#x2004;" horiz-adv-x="434" />
+<glyph unicode="&#x2005;" horiz-adv-x="326" />
+<glyph unicode="&#x2006;" horiz-adv-x="217" />
+<glyph unicode="&#x2007;" horiz-adv-x="217" />
+<glyph unicode="&#x2008;" horiz-adv-x="163" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="326" />
+<glyph unicode="&#x20ac;" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
+<glyph unicode="&#x2212;" d="M200 400h900v300h-900v-300z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
+<glyph unicode="&#x2709;" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
+<glyph unicode="&#x270f;" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
+<glyph unicode="&#xe001;" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
+<glyph unicode="&#xe002;" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
+<glyph unicode="&#xe003;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
+<glyph unicode="&#xe005;" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
+<glyph unicode="&#xe006;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
+<glyph unicode="&#xe007;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
+<glyph unicode="&#xe008;" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
+<glyph unicode="&#xe009;" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
+<glyph unicode="&#xe010;" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe011;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe012;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe013;" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
+<glyph unicode="&#xe014;" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
+<glyph unicode="&#xe015;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
+<glyph unicode="&#xe016;" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
+<glyph unicode="&#xe017;" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
+<glyph unicode="&#xe018;" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
+<glyph unicode="&#xe019;" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
+<glyph unicode="&#xe020;" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
+<glyph unicode="&#xe021;" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
+<glyph unicode="&#xe022;" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
+<glyph unicode="&#xe023;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
+<glyph unicode="&#xe024;" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
+<glyph unicode="&#xe026;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
+<glyph unicode="&#xe027;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
+<glyph unicode="&#xe028;" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
+<glyph unicode="&#xe029;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
+<glyph unicode="&#xe030;" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
+<glyph unicode="&#xe031;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
+<glyph unicode="&#xe032;" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
+<glyph unicode="&#xe033;" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
+<glyph unicode="&#xe034;" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
+<glyph unicode="&#xe035;" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
+<glyph unicode="&#xe036;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
+<glyph unicode="&#xe037;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
+<glyph unicode="&#xe038;" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
+<glyph unicode="&#xe039;" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
+<glyph unicode="&#xe040;" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
+<glyph unicode="&#xe041;" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
+<glyph unicode="&#xe042;" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
+<glyph unicode="&#xe043;" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
+<glyph unicode="&#xe044;" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
+<glyph unicode="&#xe045;" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
+<glyph unicode="&#xe046;" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
+<glyph unicode="&#xe047;" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
+<glyph unicode="&#xe048;" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
+<glyph unicode="&#xe049;" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
+<glyph unicode="&#xe050;" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
+<glyph unicode="&#xe051;" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
+<glyph unicode="&#xe052;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe053;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe054;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe055;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe056;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe057;" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe058;" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
+<glyph unicode="&#xe059;" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
+<glyph unicode="&#xe062;" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
+<glyph unicode="&#xe063;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
+<glyph unicode="&#xe064;" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
+<glyph unicode="&#xe065;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
+<glyph unicode="&#xe066;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
+<glyph unicode="&#xe067;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
+<glyph unicode="&#xe068;" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
+<glyph unicode="&#xe069;" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe070;" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe071;" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
+<glyph unicode="&#xe072;" d="M200 0l900 550l-900 550v-1100z" />
+<glyph unicode="&#xe073;" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe074;" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe075;" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
+<glyph unicode="&#xe076;" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
+<glyph unicode="&#xe077;" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
+<glyph unicode="&#xe078;" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
+<glyph unicode="&#xe079;" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
+<glyph unicode="&#xe080;" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
+<glyph unicode="&#xe081;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
+<glyph unicode="&#xe082;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
+<glyph unicode="&#xe083;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
+<glyph unicode="&#xe084;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
+<glyph unicode="&#xe085;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
+<glyph unicode="&#xe086;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
+<glyph unicode="&#xe087;" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
+<glyph unicode="&#xe088;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
+<glyph unicode="&#xe089;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
+<glyph unicode="&#xe090;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
+<glyph unicode="&#xe091;" d="M0 547l600 453v-300h600v-300h-600v-301z" />
+<glyph unicode="&#xe092;" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
+<glyph unicode="&#xe093;" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
+<glyph unicode="&#xe094;" d="M104 600h296v600h300v-600h298l-449 -600z" />
+<glyph unicode="&#xe095;" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
+<glyph unicode="&#xe096;" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
+<glyph unicode="&#xe097;" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
+<glyph unicode="&#xe101;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
+<glyph unicode="&#xe102;" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
+<glyph unicode="&#xe103;" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
+<glyph unicode="&#xe104;" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
+<glyph unicode="&#xe105;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
+<glyph unicode="&#xe106;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
+<glyph unicode="&#xe107;" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
+<glyph unicode="&#xe108;" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
+<glyph unicode="&#xe109;" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
+<glyph unicode="&#xe110;" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
+<glyph unicode="&#xe111;" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
+<glyph unicode="&#xe112;" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
+<glyph unicode="&#xe113;" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
+<glyph unicode="&#xe114;" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
+<glyph unicode="&#xe115;" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
+<glyph unicode="&#xe116;" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
+<glyph unicode="&#xe117;" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
+<glyph unicode="&#xe118;" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
+<glyph unicode="&#xe119;" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
+<glyph unicode="&#xe120;" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
+<glyph unicode="&#xe121;" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
+<glyph unicode="&#xe122;" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe123;" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
+<glyph unicode="&#xe124;" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
+<glyph unicode="&#xe125;" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
+<glyph unicode="&#xe126;" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
+<glyph unicode="&#xe127;" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
+<glyph unicode="&#xe128;" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
+<glyph unicode="&#xe129;" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
+<glyph unicode="&#xe130;" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
+<glyph unicode="&#xe131;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
+<glyph unicode="&#xe132;" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
+<glyph unicode="&#xe133;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
+<glyph unicode="&#xe134;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
+<glyph unicode="&#xe135;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
+<glyph unicode="&#xe136;" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
+<glyph unicode="&#xe138;" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
+<glyph unicode="&#xe139;" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
+<glyph unicode="&#xe140;" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
+<glyph unicode="&#xe141;" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
+<glyph unicode="&#xe142;" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
+<glyph unicode="&#xe143;" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
+<glyph unicode="&#xe144;" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
+<glyph unicode="&#xe145;" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
+<glyph unicode="&#xe146;" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
+<glyph unicode="&#xe148;" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
+<glyph unicode="&#xe149;" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
+<glyph unicode="&#xe150;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
+<glyph unicode="&#xe151;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
+<glyph unicode="&#xe152;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
+<glyph unicode="&#xe153;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
+<glyph unicode="&#xe154;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
+<glyph unicode="&#xe155;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
+<glyph unicode="&#xe156;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
+<glyph unicode="&#xe157;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
+<glyph unicode="&#xe158;" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
+<glyph unicode="&#xe159;" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
+<glyph unicode="&#xe160;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
+<glyph unicode="&#xe161;" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
+<glyph unicode="&#xe162;" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
+<glyph unicode="&#xe163;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
+<glyph unicode="&#xe164;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
+<glyph unicode="&#xe165;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
+<glyph unicode="&#xe166;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe167;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe168;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe169;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe170;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe171;" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
+<glyph unicode="&#xe172;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe173;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe174;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
+<glyph unicode="&#xe175;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe176;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe177;" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
+<glyph unicode="&#xe178;" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
+<glyph unicode="&#xe179;" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
+<glyph unicode="&#xe180;" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
+<glyph unicode="&#xe181;" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
+<glyph unicode="&#xe182;" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
+<glyph unicode="&#xe183;" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
+<glyph unicode="&#xe184;" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
+<glyph unicode="&#xe185;" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
+<glyph unicode="&#xe186;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe187;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe188;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
+<glyph unicode="&#xe189;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
+<glyph unicode="&#xe190;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
+<glyph unicode="&#xe191;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe192;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe193;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
+<glyph unicode="&#xe194;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
+<glyph unicode="&#xe195;" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
+<glyph unicode="&#xe197;" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
+<glyph unicode="&#xe198;" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
+<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
+<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf b/bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000..67fa00b
--- /dev/null
+++ b/bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff b/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000..8c54182
--- /dev/null
+++ b/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/bower_components/bootstrap/grunt/bs-glyphicons-data-generator.js b/bower_components/bootstrap/grunt/bs-glyphicons-data-generator.js
new file mode 100644
index 0000000..16a0ca2
--- /dev/null
+++ b/bower_components/bootstrap/grunt/bs-glyphicons-data-generator.js
@@ -0,0 +1,34 @@
+/*!
+ * Bootstrap Grunt task for Glyphicons data generation
+ * http://getbootstrap.com
+ * Copyright 2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+'use strict';
+var fs = require('fs');
+
+module.exports = function generateGlyphiconsData() {
+ // Pass encoding, utf8, so `readFileSync` will return a string instead of a
+ // buffer
+ var glyphiconsFile = fs.readFileSync('less/glyphicons.less', 'utf8');
+ var glpyhiconsLines = glyphiconsFile.split('\n');
+
+ // Use any line that starts with ".glyphicon-" and capture the class name
+ var iconClassName = /^\.(glyphicon-[^\s]+)/;
+ var glyphiconsData = '# This file is generated via Grunt task. **Do not edit directly.**\n' +
+ '# See the \'build-glyphicons-data\' task in Gruntfile.js.\n\n';
+ for (var i = 0, len = glpyhiconsLines.length; i < len; i++) {
+ var match = glpyhiconsLines[i].match(iconClassName);
+
+ if (match !== null) {
+ glyphiconsData += '- ' + match[1] + '\n';
+ }
+ }
+
+ // Create the `_data` directory if it doesn't already exist
+ if (!fs.existsSync('docs/_data')) {
+ fs.mkdirSync('docs/_data');
+ }
+
+ fs.writeFileSync('docs/_data/glyphicons.yml', glyphiconsData);
+};
diff --git a/bower_components/bootstrap/grunt/bs-lessdoc-parser.js b/bower_components/bootstrap/grunt/bs-lessdoc-parser.js
new file mode 100644
index 0000000..5a86f13
--- /dev/null
+++ b/bower_components/bootstrap/grunt/bs-lessdoc-parser.js
@@ -0,0 +1,236 @@
+/*!
+ * Bootstrap Grunt task for parsing Less docstrings
+ * http://getbootstrap.com
+ * Copyright 2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+'use strict';
+
+var markdown = require('markdown').markdown;
+
+function markdown2html(markdownString) {
+ // the slice removes the <p>...</p> wrapper output by Markdown processor
+ return markdown.toHTML(markdownString.trim()).slice(3, -4);
+}
+
+
+/*
+Mini-language:
+ //== This is a normal heading, which starts a section. Sections group variables together.
+ //## Optional description for the heading
+
+ //=== This is a subheading.
+
+ //** Optional description for the following variable. You **can** use Markdown in descriptions to discuss `<html>` stuff.
+ @foo: #ffff;
+
+ //-- This is a heading for a section whose variables shouldn't be customizable
+
+ All other lines are ignored completely.
+*/
+
+
+var CUSTOMIZABLE_HEADING = /^[/]{2}={2}(.*)$/;
+var UNCUSTOMIZABLE_HEADING = /^[/]{2}-{2}(.*)$/;
+var SUBSECTION_HEADING = /^[/]{2}={3}(.*)$/;
+var SECTION_DOCSTRING = /^[/]{2}#{2}(.*)$/;
+var VAR_ASSIGNMENT = /^(@[a-zA-Z0-9_-]+):[ ]*([^ ;][^;]+);[ ]*$/;
+var VAR_DOCSTRING = /^[/]{2}[*]{2}(.*)$/;
+
+function Section(heading, customizable) {
+ this.heading = heading.trim();
+ this.id = this.heading.replace(/\s+/g, '-').toLowerCase();
+ this.customizable = customizable;
+ this.docstring = null;
+ this.subsections = [];
+}
+
+Section.prototype.addSubSection = function (subsection) {
+ this.subsections.push(subsection);
+};
+
+function SubSection(heading) {
+ this.heading = heading.trim();
+ this.id = this.heading.replace(/\s+/g, '-').toLowerCase();
+ this.variables = [];
+}
+
+SubSection.prototype.addVar = function (variable) {
+ this.variables.push(variable);
+};
+
+function VarDocstring(markdownString) {
+ this.html = markdown2html(markdownString);
+}
+
+function SectionDocstring(markdownString) {
+ this.html = markdown2html(markdownString);
+}
+
+function Variable(name, defaultValue) {
+ this.name = name;
+ this.defaultValue = defaultValue;
+ this.docstring = null;
+}
+
+function Tokenizer(fileContent) {
+ this._lines = fileContent.split('\n');
+ this._next = undefined;
+}
+
+Tokenizer.prototype.unshift = function (token) {
+ if (this._next !== undefined) {
+ throw new Error('Attempted to unshift twice!');
+ }
+ this._next = token;
+};
+
+Tokenizer.prototype._shift = function () {
+ // returning null signals EOF
+ // returning undefined means the line was ignored
+ if (this._next !== undefined) {
+ var result = this._next;
+ this._next = undefined;
+ return result;
+ }
+ if (this._lines.length <= 0) {
+ return null;
+ }
+ var line = this._lines.shift();
+ var match = null;
+ match = SUBSECTION_HEADING.exec(line);
+ if (match !== null) {
+ return new SubSection(match[1]);
+ }
+ match = CUSTOMIZABLE_HEADING.exec(line);
+ if (match !== null) {
+ return new Section(match[1], true);
+ }
+ match = UNCUSTOMIZABLE_HEADING.exec(line);
+ if (match !== null) {
+ return new Section(match[1], false);
+ }
+ match = SECTION_DOCSTRING.exec(line);
+ if (match !== null) {
+ return new SectionDocstring(match[1]);
+ }
+ match = VAR_DOCSTRING.exec(line);
+ if (match !== null) {
+ return new VarDocstring(match[1]);
+ }
+ var commentStart = line.lastIndexOf('//');
+ var varLine = (commentStart === -1) ? line : line.slice(0, commentStart);
+ match = VAR_ASSIGNMENT.exec(varLine);
+ if (match !== null) {
+ return new Variable(match[1], match[2]);
+ }
+ return undefined;
+};
+
+Tokenizer.prototype.shift = function () {
+ while (true) {
+ var result = this._shift();
+ if (result === undefined) {
+ continue;
+ }
+ return result;
+ }
+};
+
+function Parser(fileContent) {
+ this._tokenizer = new Tokenizer(fileContent);
+}
+
+Parser.prototype.parseFile = function () {
+ var sections = [];
+ while (true) {
+ var section = this.parseSection();
+ if (section === null) {
+ if (this._tokenizer.shift() !== null) {
+ throw new Error('Unexpected unparsed section of file remains!');
+ }
+ return sections;
+ }
+ sections.push(section);
+ }
+};
+
+Parser.prototype.parseSection = function () {
+ var section = this._tokenizer.shift();
+ if (section === null) {
+ return null;
+ }
+ if (!(section instanceof Section)) {
+ throw new Error('Expected section heading; got: ' + JSON.stringify(section));
+ }
+ var docstring = this._tokenizer.shift();
+ if (docstring instanceof SectionDocstring) {
+ section.docstring = docstring;
+ }
+ else {
+ this._tokenizer.unshift(docstring);
+ }
+ this.parseSubSections(section);
+
+ return section;
+};
+
+Parser.prototype.parseSubSections = function (section) {
+ while (true) {
+ var subsection = this.parseSubSection();
+ if (subsection === null) {
+ if (section.subsections.length === 0) {
+ // Presume an implicit initial subsection
+ subsection = new SubSection('');
+ this.parseVars(subsection);
+ }
+ else {
+ break;
+ }
+ }
+ section.addSubSection(subsection);
+ }
+
+ if (section.subsections.length === 1 && !(section.subsections[0].heading) && section.subsections[0].variables.length === 0) {
+ // Ignore lone empty implicit subsection
+ section.subsections = [];
+ }
+};
+
+Parser.prototype.parseSubSection = function () {
+ var subsection = this._tokenizer.shift();
+ if (subsection instanceof SubSection) {
+ this.parseVars(subsection);
+ return subsection;
+ }
+ this._tokenizer.unshift(subsection);
+ return null;
+};
+
+Parser.prototype.parseVars = function (subsection) {
+ while (true) {
+ var variable = this.parseVar();
+ if (variable === null) {
+ return;
+ }
+ subsection.addVar(variable);
+ }
+};
+
+Parser.prototype.parseVar = function () {
+ var docstring = this._tokenizer.shift();
+ if (!(docstring instanceof VarDocstring)) {
+ this._tokenizer.unshift(docstring);
+ docstring = null;
+ }
+ var variable = this._tokenizer.shift();
+ if (variable instanceof Variable) {
+ variable.docstring = docstring;
+ return variable;
+ }
+ this._tokenizer.unshift(variable);
+ return null;
+};
+
+
+module.exports = Parser;
diff --git a/bower_components/bootstrap/grunt/bs-raw-files-generator.js b/bower_components/bootstrap/grunt/bs-raw-files-generator.js
new file mode 100644
index 0000000..b5b3309
--- /dev/null
+++ b/bower_components/bootstrap/grunt/bs-raw-files-generator.js
@@ -0,0 +1,31 @@
+/* global btoa: true */
+/*!
+ * Bootstrap Grunt task for generating raw-files.min.js for the Customizer
+ * http://getbootstrap.com
+ * Copyright 2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+'use strict';
+var btoa = require('btoa');
+var fs = require('fs');
+
+function getFiles(type) {
+ var files = {};
+ fs.readdirSync(type)
+ .filter(function (path) {
+ return type === 'fonts' ? true : new RegExp('\\.' + type + '$').test(path);
+ })
+ .forEach(function (path) {
+ var fullPath = type + '/' + path;
+ files[path] = (type === 'fonts' ? btoa(fs.readFileSync(fullPath)) : fs.readFileSync(fullPath, 'utf8'));
+ });
+ return 'var __' + type + ' = ' + JSON.stringify(files) + '\n';
+}
+
+module.exports = function generateRawFilesJs(banner) {
+ if (!banner) {
+ banner = '';
+ }
+ var files = banner + getFiles('js') + getFiles('less') + getFiles('fonts');
+ fs.writeFileSync('docs/assets/js/raw-files.min.js', files);
+};
diff --git a/bower_components/bootstrap/grunt/shrinkwrap.js b/bower_components/bootstrap/grunt/shrinkwrap.js
new file mode 100644
index 0000000..d3292b4
--- /dev/null
+++ b/bower_components/bootstrap/grunt/shrinkwrap.js
@@ -0,0 +1,28 @@
+/*!
+ * Bootstrap Grunt task for generating npm-shrinkwrap.canonical.json
+ * http://getbootstrap.com
+ * Copyright 2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+/*
+This Grunt task updates the npm-shrinkwrap.canonical.json file that's used as the key for Bootstrap's npm packages cache.
+This task should be run and the updated file should be committed whenever Bootstrap's dependencies change.
+*/
+'use strict';
+var canonicallyJsonStringify = require('canonical-json');
+var NON_CANONICAL_FILE = 'npm-shrinkwrap.json';
+var DEST_FILE = 'test-infra/npm-shrinkwrap.canonical.json';
+
+
+function updateShrinkwrap(grunt) {
+ // Assumption: Non-canonical shrinkwrap already generated by prerequisite Grunt task
+ var shrinkwrapData = grunt.file.readJSON(NON_CANONICAL_FILE);
+ grunt.log.writeln('Deleting ' + NON_CANONICAL_FILE.cyan + '...');
+ grunt.file.delete(NON_CANONICAL_FILE);
+ // Output as Canonical JSON in correct location
+ grunt.file.write(DEST_FILE, canonicallyJsonStringify(shrinkwrapData));
+ grunt.log.writeln('File ' + DEST_FILE.cyan + ' updated.');
+}
+
+
+module.exports = updateShrinkwrap;
diff --git a/bower_components/bootstrap/js/affix.js b/bower_components/bootstrap/js/affix.js
new file mode 100644
index 0000000..05c909e
--- /dev/null
+++ b/bower_components/bootstrap/js/affix.js
@@ -0,0 +1,137 @@
+/* ========================================================================
+ * Bootstrap: affix.js v3.1.1
+ * http://getbootstrap.com/javascript/#affix
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // AFFIX CLASS DEFINITION
+ // ======================
+
+ var Affix = function (element, options) {
+ this.options = $.extend({}, Affix.DEFAULTS, options)
+ this.$window = $(window)
+ .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
+ .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
+
+ this.$element = $(element)
+ this.affixed =
+ this.unpin =
+ this.pinnedOffset = null
+
+ this.checkPosition()
+ }
+
+ Affix.RESET = 'affix affix-top affix-bottom'
+
+ Affix.DEFAULTS = {
+ offset: 0
+ }
+
+ Affix.prototype.getPinnedOffset = function () {
+ if (this.pinnedOffset) return this.pinnedOffset
+ this.$element.removeClass(Affix.RESET).addClass('affix')
+ var scrollTop = this.$window.scrollTop()
+ var position = this.$element.offset()
+ return (this.pinnedOffset = position.top - scrollTop)
+ }
+
+ Affix.prototype.checkPositionWithEventLoop = function () {
+ setTimeout($.proxy(this.checkPosition, this), 1)
+ }
+
+ Affix.prototype.checkPosition = function () {
+ if (!this.$element.is(':visible')) return
+
+ var scrollHeight = $(document).height()
+ var scrollTop = this.$window.scrollTop()
+ var position = this.$element.offset()
+ var offset = this.options.offset
+ var offsetTop = offset.top
+ var offsetBottom = offset.bottom
+
+ if (this.affixed == 'top') position.top += scrollTop
+
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
+ if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
+
+ var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false :
+ offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
+ offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false
+
+ if (this.affixed === affix) return
+ if (this.unpin) this.$element.css('top', '')
+
+ var affixType = 'affix' + (affix ? '-' + affix : '')
+ var e = $.Event(affixType + '.bs.affix')
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ this.affixed = affix
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
+
+ this.$element
+ .removeClass(Affix.RESET)
+ .addClass(affixType)
+ .trigger($.Event(affixType.replace('affix', 'affixed')))
+
+ if (affix == 'bottom') {
+ this.$element.offset({ top: scrollHeight - offsetBottom - this.$element.height() })
+ }
+ }
+
+
+ // AFFIX PLUGIN DEFINITION
+ // =======================
+
+ var old = $.fn.affix
+
+ $.fn.affix = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.affix')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.affix.Constructor = Affix
+
+
+ // AFFIX NO CONFLICT
+ // =================
+
+ $.fn.affix.noConflict = function () {
+ $.fn.affix = old
+ return this
+ }
+
+
+ // AFFIX DATA-API
+ // ==============
+
+ $(window).on('load', function () {
+ $('[data-spy="affix"]').each(function () {
+ var $spy = $(this)
+ var data = $spy.data()
+
+ data.offset = data.offset || {}
+
+ if (data.offsetBottom) data.offset.bottom = data.offsetBottom
+ if (data.offsetTop) data.offset.top = data.offsetTop
+
+ $spy.affix(data)
+ })
+ })
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/alert.js b/bower_components/bootstrap/js/alert.js
new file mode 100644
index 0000000..516fe4f
--- /dev/null
+++ b/bower_components/bootstrap/js/alert.js
@@ -0,0 +1,88 @@
+/* ========================================================================
+ * Bootstrap: alert.js v3.1.1
+ * http://getbootstrap.com/javascript/#alerts
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // ALERT CLASS DEFINITION
+ // ======================
+
+ var dismiss = '[data-dismiss="alert"]'
+ var Alert = function (el) {
+ $(el).on('click', dismiss, this.close)
+ }
+
+ Alert.prototype.close = function (e) {
+ var $this = $(this)
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ var $parent = $(selector)
+
+ if (e) e.preventDefault()
+
+ if (!$parent.length) {
+ $parent = $this.hasClass('alert') ? $this : $this.parent()
+ }
+
+ $parent.trigger(e = $.Event('close.bs.alert'))
+
+ if (e.isDefaultPrevented()) return
+
+ $parent.removeClass('in')
+
+ function removeElement() {
+ $parent.trigger('closed.bs.alert').remove()
+ }
+
+ $.support.transition && $parent.hasClass('fade') ?
+ $parent
+ .one($.support.transition.end, removeElement)
+ .emulateTransitionEnd(150) :
+ removeElement()
+ }
+
+
+ // ALERT PLUGIN DEFINITION
+ // =======================
+
+ var old = $.fn.alert
+
+ $.fn.alert = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.alert')
+
+ if (!data) $this.data('bs.alert', (data = new Alert(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ $.fn.alert.Constructor = Alert
+
+
+ // ALERT NO CONFLICT
+ // =================
+
+ $.fn.alert.noConflict = function () {
+ $.fn.alert = old
+ return this
+ }
+
+
+ // ALERT DATA-API
+ // ==============
+
+ $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/button.js b/bower_components/bootstrap/js/button.js
new file mode 100644
index 0000000..f4d8d8b
--- /dev/null
+++ b/bower_components/bootstrap/js/button.js
@@ -0,0 +1,107 @@
+/* ========================================================================
+ * Bootstrap: button.js v3.1.1
+ * http://getbootstrap.com/javascript/#buttons
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // BUTTON PUBLIC CLASS DEFINITION
+ // ==============================
+
+ var Button = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, Button.DEFAULTS, options)
+ this.isLoading = false
+ }
+
+ Button.DEFAULTS = {
+ loadingText: 'loading...'
+ }
+
+ Button.prototype.setState = function (state) {
+ var d = 'disabled'
+ var $el = this.$element
+ var val = $el.is('input') ? 'val' : 'html'
+ var data = $el.data()
+
+ state = state + 'Text'
+
+ if (!data.resetText) $el.data('resetText', $el[val]())
+
+ $el[val](data[state] || this.options[state])
+
+ // push to event loop to allow forms to submit
+ setTimeout($.proxy(function () {
+ if (state == 'loadingText') {
+ this.isLoading = true
+ $el.addClass(d).attr(d, d)
+ } else if (this.isLoading) {
+ this.isLoading = false
+ $el.removeClass(d).removeAttr(d)
+ }
+ }, this), 0)
+ }
+
+ Button.prototype.toggle = function () {
+ var changed = true
+ var $parent = this.$element.closest('[data-toggle="buttons"]')
+
+ if ($parent.length) {
+ var $input = this.$element.find('input')
+ if ($input.prop('type') == 'radio') {
+ if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
+ else $parent.find('.active').removeClass('active')
+ }
+ if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
+ }
+
+ if (changed) this.$element.toggleClass('active')
+ }
+
+
+ // BUTTON PLUGIN DEFINITION
+ // ========================
+
+ var old = $.fn.button
+
+ $.fn.button = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.button')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.button', (data = new Button(this, options)))
+
+ if (option == 'toggle') data.toggle()
+ else if (option) data.setState(option)
+ })
+ }
+
+ $.fn.button.Constructor = Button
+
+
+ // BUTTON NO CONFLICT
+ // ==================
+
+ $.fn.button.noConflict = function () {
+ $.fn.button = old
+ return this
+ }
+
+
+ // BUTTON DATA-API
+ // ===============
+
+ $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
+ var $btn = $(e.target)
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+ $btn.button('toggle')
+ e.preventDefault()
+ })
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/carousel.js b/bower_components/bootstrap/js/carousel.js
new file mode 100644
index 0000000..19e9af1
--- /dev/null
+++ b/bower_components/bootstrap/js/carousel.js
@@ -0,0 +1,205 @@
+/* ========================================================================
+ * Bootstrap: carousel.js v3.1.1
+ * http://getbootstrap.com/javascript/#carousel
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // CAROUSEL CLASS DEFINITION
+ // =========================
+
+ var Carousel = function (element, options) {
+ this.$element = $(element)
+ this.$indicators = this.$element.find('.carousel-indicators')
+ this.options = options
+ this.paused =
+ this.sliding =
+ this.interval =
+ this.$active =
+ this.$items = null
+
+ this.options.pause == 'hover' && this.$element
+ .on('mouseenter', $.proxy(this.pause, this))
+ .on('mouseleave', $.proxy(this.cycle, this))
+ }
+
+ Carousel.DEFAULTS = {
+ interval: 5000,
+ pause: 'hover',
+ wrap: true
+ }
+
+ Carousel.prototype.cycle = function (e) {
+ e || (this.paused = false)
+
+ this.interval && clearInterval(this.interval)
+
+ this.options.interval
+ && !this.paused
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+
+ return this
+ }
+
+ Carousel.prototype.getActiveIndex = function () {
+ this.$active = this.$element.find('.item.active')
+ this.$items = this.$active.parent().children()
+
+ return this.$items.index(this.$active)
+ }
+
+ Carousel.prototype.to = function (pos) {
+ var that = this
+ var activeIndex = this.getActiveIndex()
+
+ if (pos > (this.$items.length - 1) || pos < 0) return
+
+ if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) })
+ if (activeIndex == pos) return this.pause().cycle()
+
+ return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
+ }
+
+ Carousel.prototype.pause = function (e) {
+ e || (this.paused = true)
+
+ if (this.$element.find('.next, .prev').length && $.support.transition) {
+ this.$element.trigger($.support.transition.end)
+ this.cycle(true)
+ }
+
+ this.interval = clearInterval(this.interval)
+
+ return this
+ }
+
+ Carousel.prototype.next = function () {
+ if (this.sliding) return
+ return this.slide('next')
+ }
+
+ Carousel.prototype.prev = function () {
+ if (this.sliding) return
+ return this.slide('prev')
+ }
+
+ Carousel.prototype.slide = function (type, next) {
+ var $active = this.$element.find('.item.active')
+ var $next = next || $active[type]()
+ var isCycling = this.interval
+ var direction = type == 'next' ? 'left' : 'right'
+ var fallback = type == 'next' ? 'first' : 'last'
+ var that = this
+
+ if (!$next.length) {
+ if (!this.options.wrap) return
+ $next = this.$element.find('.item')[fallback]()
+ }
+
+ if ($next.hasClass('active')) return this.sliding = false
+
+ var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction })
+ this.$element.trigger(e)
+ if (e.isDefaultPrevented()) return
+
+ this.sliding = true
+
+ isCycling && this.pause()
+
+ if (this.$indicators.length) {
+ this.$indicators.find('.active').removeClass('active')
+ this.$element.one('slid.bs.carousel', function () {
+ var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
+ $nextIndicator && $nextIndicator.addClass('active')
+ })
+ }
+
+ if ($.support.transition && this.$element.hasClass('slide')) {
+ $next.addClass(type)
+ $next[0].offsetWidth // force reflow
+ $active.addClass(direction)
+ $next.addClass(direction)
+ $active
+ .one($.support.transition.end, function () {
+ $next.removeClass([type, direction].join(' ')).addClass('active')
+ $active.removeClass(['active', direction].join(' '))
+ that.sliding = false
+ setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0)
+ })
+ .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
+ } else {
+ $active.removeClass('active')
+ $next.addClass('active')
+ this.sliding = false
+ this.$element.trigger('slid.bs.carousel')
+ }
+
+ isCycling && this.cycle()
+
+ return this
+ }
+
+
+ // CAROUSEL PLUGIN DEFINITION
+ // ==========================
+
+ var old = $.fn.carousel
+
+ $.fn.carousel = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.carousel')
+ var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
+ var action = typeof option == 'string' ? option : options.slide
+
+ if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
+ if (typeof option == 'number') data.to(option)
+ else if (action) data[action]()
+ else if (options.interval) data.pause().cycle()
+ })
+ }
+
+ $.fn.carousel.Constructor = Carousel
+
+
+ // CAROUSEL NO CONFLICT
+ // ====================
+
+ $.fn.carousel.noConflict = function () {
+ $.fn.carousel = old
+ return this
+ }
+
+
+ // CAROUSEL DATA-API
+ // =================
+
+ $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
+ var $this = $(this), href
+ var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+ var options = $.extend({}, $target.data(), $this.data())
+ var slideIndex = $this.attr('data-slide-to')
+ if (slideIndex) options.interval = false
+
+ $target.carousel(options)
+
+ if (slideIndex = $this.attr('data-slide-to')) {
+ $target.data('bs.carousel').to(slideIndex)
+ }
+
+ e.preventDefault()
+ })
+
+ $(window).on('load', function () {
+ $('[data-ride="carousel"]').each(function () {
+ var $carousel = $(this)
+ $carousel.carousel($carousel.data())
+ })
+ })
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/collapse.js b/bower_components/bootstrap/js/collapse.js
new file mode 100644
index 0000000..7130282
--- /dev/null
+++ b/bower_components/bootstrap/js/collapse.js
@@ -0,0 +1,170 @@
+/* ========================================================================
+ * Bootstrap: collapse.js v3.1.1
+ * http://getbootstrap.com/javascript/#collapse
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // COLLAPSE PUBLIC CLASS DEFINITION
+ // ================================
+
+ var Collapse = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, Collapse.DEFAULTS, options)
+ this.transitioning = null
+
+ if (this.options.parent) this.$parent = $(this.options.parent)
+ if (this.options.toggle) this.toggle()
+ }
+
+ Collapse.DEFAULTS = {
+ toggle: true
+ }
+
+ Collapse.prototype.dimension = function () {
+ var hasWidth = this.$element.hasClass('width')
+ return hasWidth ? 'width' : 'height'
+ }
+
+ Collapse.prototype.show = function () {
+ if (this.transitioning || this.$element.hasClass('in')) return
+
+ var startEvent = $.Event('show.bs.collapse')
+ this.$element.trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
+
+ var actives = this.$parent && this.$parent.find('> .panel > .in')
+
+ if (actives && actives.length) {
+ var hasData = actives.data('bs.collapse')
+ if (hasData && hasData.transitioning) return
+ actives.collapse('hide')
+ hasData || actives.data('bs.collapse', null)
+ }
+
+ var dimension = this.dimension()
+
+ this.$element
+ .removeClass('collapse')
+ .addClass('collapsing')
+ [dimension](0)
+
+ this.transitioning = 1
+
+ var complete = function () {
+ this.$element
+ .removeClass('collapsing')
+ .addClass('collapse in')
+ [dimension]('auto')
+ this.transitioning = 0
+ this.$element.trigger('shown.bs.collapse')
+ }
+
+ if (!$.support.transition) return complete.call(this)
+
+ var scrollSize = $.camelCase(['scroll', dimension].join('-'))
+
+ this.$element
+ .one($.support.transition.end, $.proxy(complete, this))
+ .emulateTransitionEnd(350)
+ [dimension](this.$element[0][scrollSize])
+ }
+
+ Collapse.prototype.hide = function () {
+ if (this.transitioning || !this.$element.hasClass('in')) return
+
+ var startEvent = $.Event('hide.bs.collapse')
+ this.$element.trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
+
+ var dimension = this.dimension()
+
+ this.$element
+ [dimension](this.$element[dimension]())
+ [0].offsetHeight
+
+ this.$element
+ .addClass('collapsing')
+ .removeClass('collapse')
+ .removeClass('in')
+
+ this.transitioning = 1
+
+ var complete = function () {
+ this.transitioning = 0
+ this.$element
+ .trigger('hidden.bs.collapse')
+ .removeClass('collapsing')
+ .addClass('collapse')
+ }
+
+ if (!$.support.transition) return complete.call(this)
+
+ this.$element
+ [dimension](0)
+ .one($.support.transition.end, $.proxy(complete, this))
+ .emulateTransitionEnd(350)
+ }
+
+ Collapse.prototype.toggle = function () {
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
+ }
+
+
+ // COLLAPSE PLUGIN DEFINITION
+ // ==========================
+
+ var old = $.fn.collapse
+
+ $.fn.collapse = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.collapse')
+ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data && options.toggle && option == 'show') option = !option
+ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.collapse.Constructor = Collapse
+
+
+ // COLLAPSE NO CONFLICT
+ // ====================
+
+ $.fn.collapse.noConflict = function () {
+ $.fn.collapse = old
+ return this
+ }
+
+
+ // COLLAPSE DATA-API
+ // =================
+
+ $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) {
+ var $this = $(this), href
+ var target = $this.attr('data-target')
+ || e.preventDefault()
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
+ var $target = $(target)
+ var data = $target.data('bs.collapse')
+ var option = data ? 'toggle' : $this.data()
+ var parent = $this.attr('data-parent')
+ var $parent = parent && $(parent)
+
+ if (!data || !data.transitioning) {
+ if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed')
+ $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
+ }
+
+ $target.collapse(option)
+ })
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/dropdown.js b/bower_components/bootstrap/js/dropdown.js
new file mode 100644
index 0000000..43d7ae3
--- /dev/null
+++ b/bower_components/bootstrap/js/dropdown.js
@@ -0,0 +1,147 @@
+/* ========================================================================
+ * Bootstrap: dropdown.js v3.1.1
+ * http://getbootstrap.com/javascript/#dropdowns
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // DROPDOWN CLASS DEFINITION
+ // =========================
+
+ var backdrop = '.dropdown-backdrop'
+ var toggle = '[data-toggle=dropdown]'
+ var Dropdown = function (element) {
+ $(element).on('click.bs.dropdown', this.toggle)
+ }
+
+ Dropdown.prototype.toggle = function (e) {
+ var $this = $(this)
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ clearMenus()
+
+ if (!isActive) {
+ if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
+ // if mobile we use a backdrop because click events don't delegate
+ $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
+ }
+
+ var relatedTarget = { relatedTarget: this }
+ $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
+
+ if (e.isDefaultPrevented()) return
+
+ $parent
+ .toggleClass('open')
+ .trigger('shown.bs.dropdown', relatedTarget)
+
+ $this.focus()
+ }
+
+ return false
+ }
+
+ Dropdown.prototype.keydown = function (e) {
+ if (!/(38|40|27)/.test(e.keyCode)) return
+
+ var $this = $(this)
+
+ e.preventDefault()
+ e.stopPropagation()
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ if (!isActive || (isActive && e.keyCode == 27)) {
+ if (e.which == 27) $parent.find(toggle).focus()
+ return $this.click()
+ }
+
+ var desc = ' li:not(.divider):visible a'
+ var $items = $parent.find('[role=menu]' + desc + ', [role=listbox]' + desc)
+
+ if (!$items.length) return
+
+ var index = $items.index($items.filter(':focus'))
+
+ if (e.keyCode == 38 && index > 0) index-- // up
+ if (e.keyCode == 40 && index < $items.length - 1) index++ // down
+ if (!~index) index = 0
+
+ $items.eq(index).focus()
+ }
+
+ function clearMenus(e) {
+ $(backdrop).remove()
+ $(toggle).each(function () {
+ var $parent = getParent($(this))
+ var relatedTarget = { relatedTarget: this }
+ if (!$parent.hasClass('open')) return
+ $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+ if (e.isDefaultPrevented()) return
+ $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
+ })
+ }
+
+ function getParent($this) {
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ var $parent = selector && $(selector)
+
+ return $parent && $parent.length ? $parent : $this.parent()
+ }
+
+
+ // DROPDOWN PLUGIN DEFINITION
+ // ==========================
+
+ var old = $.fn.dropdown
+
+ $.fn.dropdown = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.dropdown')
+
+ if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ // DROPDOWN NO CONFLICT
+ // ====================
+
+ $.fn.dropdown.noConflict = function () {
+ $.fn.dropdown = old
+ return this
+ }
+
+
+ // APPLY TO STANDARD DROPDOWN ELEMENTS
+ // ===================================
+
+ $(document)
+ .on('click.bs.dropdown.data-api', clearMenus)
+ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+ .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+ .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu], [role=listbox]', Dropdown.prototype.keydown)
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/modal.js b/bower_components/bootstrap/js/modal.js
new file mode 100644
index 0000000..20ff270
--- /dev/null
+++ b/bower_components/bootstrap/js/modal.js
@@ -0,0 +1,243 @@
+/* ========================================================================
+ * Bootstrap: modal.js v3.1.1
+ * http://getbootstrap.com/javascript/#modals
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // MODAL CLASS DEFINITION
+ // ======================
+
+ var Modal = function (element, options) {
+ this.options = options
+ this.$element = $(element)
+ this.$backdrop =
+ this.isShown = null
+
+ if (this.options.remote) {
+ this.$element
+ .find('.modal-content')
+ .load(this.options.remote, $.proxy(function () {
+ this.$element.trigger('loaded.bs.modal')
+ }, this))
+ }
+ }
+
+ Modal.DEFAULTS = {
+ backdrop: true,
+ keyboard: true,
+ show: true
+ }
+
+ Modal.prototype.toggle = function (_relatedTarget) {
+ return this[!this.isShown ? 'show' : 'hide'](_relatedTarget)
+ }
+
+ Modal.prototype.show = function (_relatedTarget) {
+ var that = this
+ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+
+ this.$element.trigger(e)
+
+ if (this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = true
+
+ this.escape()
+
+ this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+
+ this.backdrop(function () {
+ var transition = $.support.transition && that.$element.hasClass('fade')
+
+ if (!that.$element.parent().length) {
+ that.$element.appendTo(document.body) // don't move modals dom position
+ }
+
+ that.$element
+ .show()
+ .scrollTop(0)
+
+ if (transition) {
+ that.$element[0].offsetWidth // force reflow
+ }
+
+ that.$element
+ .addClass('in')
+ .attr('aria-hidden', false)
+
+ that.enforceFocus()
+
+ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+
+ transition ?
+ that.$element.find('.modal-dialog') // wait for modal to slide in
+ .one($.support.transition.end, function () {
+ that.$element.focus().trigger(e)
+ })
+ .emulateTransitionEnd(300) :
+ that.$element.focus().trigger(e)
+ })
+ }
+
+ Modal.prototype.hide = function (e) {
+ if (e) e.preventDefault()
+
+ e = $.Event('hide.bs.modal')
+
+ this.$element.trigger(e)
+
+ if (!this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = false
+
+ this.escape()
+
+ $(document).off('focusin.bs.modal')
+
+ this.$element
+ .removeClass('in')
+ .attr('aria-hidden', true)
+ .off('click.dismiss.bs.modal')
+
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$element
+ .one($.support.transition.end, $.proxy(this.hideModal, this))
+ .emulateTransitionEnd(300) :
+ this.hideModal()
+ }
+
+ Modal.prototype.enforceFocus = function () {
+ $(document)
+ .off('focusin.bs.modal') // guard against infinite focus loop
+ .on('focusin.bs.modal', $.proxy(function (e) {
+ if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
+ this.$element.focus()
+ }
+ }, this))
+ }
+
+ Modal.prototype.escape = function () {
+ if (this.isShown && this.options.keyboard) {
+ this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
+ e.which == 27 && this.hide()
+ }, this))
+ } else if (!this.isShown) {
+ this.$element.off('keyup.dismiss.bs.modal')
+ }
+ }
+
+ Modal.prototype.hideModal = function () {
+ var that = this
+ this.$element.hide()
+ this.backdrop(function () {
+ that.removeBackdrop()
+ that.$element.trigger('hidden.bs.modal')
+ })
+ }
+
+ Modal.prototype.removeBackdrop = function () {
+ this.$backdrop && this.$backdrop.remove()
+ this.$backdrop = null
+ }
+
+ Modal.prototype.backdrop = function (callback) {
+ var animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+ if (this.isShown && this.options.backdrop) {
+ var doAnimate = $.support.transition && animate
+
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+ .appendTo(document.body)
+
+ this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
+ if (e.target !== e.currentTarget) return
+ this.options.backdrop == 'static'
+ ? this.$element[0].focus.call(this.$element[0])
+ : this.hide.call(this)
+ }, this))
+
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+ this.$backdrop.addClass('in')
+
+ if (!callback) return
+
+ doAnimate ?
+ this.$backdrop
+ .one($.support.transition.end, callback)
+ .emulateTransitionEnd(150) :
+ callback()
+
+ } else if (!this.isShown && this.$backdrop) {
+ this.$backdrop.removeClass('in')
+
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$backdrop
+ .one($.support.transition.end, callback)
+ .emulateTransitionEnd(150) :
+ callback()
+
+ } else if (callback) {
+ callback()
+ }
+ }
+
+
+ // MODAL PLUGIN DEFINITION
+ // =======================
+
+ var old = $.fn.modal
+
+ $.fn.modal = function (option, _relatedTarget) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.modal')
+ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
+ if (typeof option == 'string') data[option](_relatedTarget)
+ else if (options.show) data.show(_relatedTarget)
+ })
+ }
+
+ $.fn.modal.Constructor = Modal
+
+
+ // MODAL NO CONFLICT
+ // =================
+
+ $.fn.modal.noConflict = function () {
+ $.fn.modal = old
+ return this
+ }
+
+
+ // MODAL DATA-API
+ // ==============
+
+ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
+ var $this = $(this)
+ var href = $this.attr('href')
+ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
+ var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+
+ if ($this.is('a')) e.preventDefault()
+
+ $target
+ .modal(option, this)
+ .one('hide', function () {
+ $this.is(':visible') && $this.focus()
+ })
+ })
+
+ $(document)
+ .on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') })
+ .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') })
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/popover.js b/bower_components/bootstrap/js/popover.js
new file mode 100644
index 0000000..23aa829
--- /dev/null
+++ b/bower_components/bootstrap/js/popover.js
@@ -0,0 +1,110 @@
+/* ========================================================================
+ * Bootstrap: popover.js v3.1.1
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // POPOVER PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Popover = function (element, options) {
+ this.init('popover', element, options)
+ }
+
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+ placement: 'right',
+ trigger: 'click',
+ content: '',
+ template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+ })
+
+
+ // NOTE: POPOVER EXTENDS tooltip.js
+ // ================================
+
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+ Popover.prototype.constructor = Popover
+
+ Popover.prototype.getDefaults = function () {
+ return Popover.DEFAULTS
+ }
+
+ Popover.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+ var content = this.getContent()
+
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+ $tip.find('.popover-content')[ // we use append for html objects to maintain js events
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+ ](content)
+
+ $tip.removeClass('fade top bottom left right in')
+
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+ // this manually by checking the contents.
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+ }
+
+ Popover.prototype.hasContent = function () {
+ return this.getTitle() || this.getContent()
+ }
+
+ Popover.prototype.getContent = function () {
+ var $e = this.$element
+ var o = this.options
+
+ return $e.attr('data-content')
+ || (typeof o.content == 'function' ?
+ o.content.call($e[0]) :
+ o.content)
+ }
+
+ Popover.prototype.arrow = function () {
+ return this.$arrow = this.$arrow || this.tip().find('.arrow')
+ }
+
+ Popover.prototype.tip = function () {
+ if (!this.$tip) this.$tip = $(this.options.template)
+ return this.$tip
+ }
+
+
+ // POPOVER PLUGIN DEFINITION
+ // =========================
+
+ var old = $.fn.popover
+
+ $.fn.popover = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.popover')
+ var options = typeof option == 'object' && option
+
+ if (!data && option == 'destroy') return
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.popover.Constructor = Popover
+
+
+ // POPOVER NO CONFLICT
+ // ===================
+
+ $.fn.popover.noConflict = function () {
+ $.fn.popover = old
+ return this
+ }
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/scrollspy.js b/bower_components/bootstrap/js/scrollspy.js
new file mode 100644
index 0000000..4346c86
--- /dev/null
+++ b/bower_components/bootstrap/js/scrollspy.js
@@ -0,0 +1,153 @@
+/* ========================================================================
+ * Bootstrap: scrollspy.js v3.1.1
+ * http://getbootstrap.com/javascript/#scrollspy
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // SCROLLSPY CLASS DEFINITION
+ // ==========================
+
+ function ScrollSpy(element, options) {
+ var href
+ var process = $.proxy(this.process, this)
+
+ this.$element = $(element).is('body') ? $(window) : $(element)
+ this.$body = $('body')
+ this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process)
+ this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
+ this.selector = (this.options.target
+ || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+ || '') + ' .nav li > a'
+ this.offsets = $([])
+ this.targets = $([])
+ this.activeTarget = null
+
+ this.refresh()
+ this.process()
+ }
+
+ ScrollSpy.DEFAULTS = {
+ offset: 10
+ }
+
+ ScrollSpy.prototype.refresh = function () {
+ var offsetMethod = this.$element[0] == window ? 'offset' : 'position'
+
+ this.offsets = $([])
+ this.targets = $([])
+
+ var self = this
+ var $targets = this.$body
+ .find(this.selector)
+ .map(function () {
+ var $el = $(this)
+ var href = $el.data('target') || $el.attr('href')
+ var $href = /^#./.test(href) && $(href)
+
+ return ($href
+ && $href.length
+ && $href.is(':visible')
+ && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
+ })
+ .sort(function (a, b) { return a[0] - b[0] })
+ .each(function () {
+ self.offsets.push(this[0])
+ self.targets.push(this[1])
+ })
+ }
+
+ ScrollSpy.prototype.process = function () {
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
+ var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
+ var maxScroll = scrollHeight - this.$scrollElement.height()
+ var offsets = this.offsets
+ var targets = this.targets
+ var activeTarget = this.activeTarget
+ var i
+
+ if (scrollTop >= maxScroll) {
+ return activeTarget != (i = targets.last()[0]) && this.activate(i)
+ }
+
+ if (activeTarget && scrollTop <= offsets[0]) {
+ return activeTarget != (i = targets[0]) && this.activate(i)
+ }
+
+ for (i = offsets.length; i--;) {
+ activeTarget != targets[i]
+ && scrollTop >= offsets[i]
+ && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
+ && this.activate( targets[i] )
+ }
+ }
+
+ ScrollSpy.prototype.activate = function (target) {
+ this.activeTarget = target
+
+ $(this.selector)
+ .parentsUntil(this.options.target, '.active')
+ .removeClass('active')
+
+ var selector = this.selector +
+ '[data-target="' + target + '"],' +
+ this.selector + '[href="' + target + '"]'
+
+ var active = $(selector)
+ .parents('li')
+ .addClass('active')
+
+ if (active.parent('.dropdown-menu').length) {
+ active = active
+ .closest('li.dropdown')
+ .addClass('active')
+ }
+
+ active.trigger('activate.bs.scrollspy')
+ }
+
+
+ // SCROLLSPY PLUGIN DEFINITION
+ // ===========================
+
+ var old = $.fn.scrollspy
+
+ $.fn.scrollspy = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.scrollspy')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.scrollspy.Constructor = ScrollSpy
+
+
+ // SCROLLSPY NO CONFLICT
+ // =====================
+
+ $.fn.scrollspy.noConflict = function () {
+ $.fn.scrollspy = old
+ return this
+ }
+
+
+ // SCROLLSPY DATA-API
+ // ==================
+
+ $(window).on('load', function () {
+ $('[data-spy="scroll"]').each(function () {
+ var $spy = $(this)
+ $spy.scrollspy($spy.data())
+ })
+ })
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/tab.js b/bower_components/bootstrap/js/tab.js
new file mode 100644
index 0000000..400cb7b
--- /dev/null
+++ b/bower_components/bootstrap/js/tab.js
@@ -0,0 +1,125 @@
+/* ========================================================================
+ * Bootstrap: tab.js v3.1.1
+ * http://getbootstrap.com/javascript/#tabs
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TAB CLASS DEFINITION
+ // ====================
+
+ var Tab = function (element) {
+ this.element = $(element)
+ }
+
+ Tab.prototype.show = function () {
+ var $this = this.element
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
+ var selector = $this.data('target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ if ($this.parent('li').hasClass('active')) return
+
+ var previous = $ul.find('.active:last a')[0]
+ var e = $.Event('show.bs.tab', {
+ relatedTarget: previous
+ })
+
+ $this.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ var $target = $(selector)
+
+ this.activate($this.parent('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $this.trigger({
+ type: 'shown.bs.tab',
+ relatedTarget: previous
+ })
+ })
+ }
+
+ Tab.prototype.activate = function (element, container, callback) {
+ var $active = container.find('> .active')
+ var transition = callback
+ && $.support.transition
+ && $active.hasClass('fade')
+
+ function next() {
+ $active
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+
+ element.addClass('active')
+
+ if (transition) {
+ element[0].offsetWidth // reflow for transition
+ element.addClass('in')
+ } else {
+ element.removeClass('fade')
+ }
+
+ if (element.parent('.dropdown-menu')) {
+ element.closest('li.dropdown').addClass('active')
+ }
+
+ callback && callback()
+ }
+
+ transition ?
+ $active
+ .one($.support.transition.end, next)
+ .emulateTransitionEnd(150) :
+ next()
+
+ $active.removeClass('in')
+ }
+
+
+ // TAB PLUGIN DEFINITION
+ // =====================
+
+ var old = $.fn.tab
+
+ $.fn.tab = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tab')
+
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tab.Constructor = Tab
+
+
+ // TAB NO CONFLICT
+ // ===============
+
+ $.fn.tab.noConflict = function () {
+ $.fn.tab = old
+ return this
+ }
+
+
+ // TAB DATA-API
+ // ============
+
+ $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+ e.preventDefault()
+ $(this).tab('show')
+ })
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/tooltip.js b/bower_components/bootstrap/js/tooltip.js
new file mode 100644
index 0000000..f6c0a37
--- /dev/null
+++ b/bower_components/bootstrap/js/tooltip.js
@@ -0,0 +1,399 @@
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.1.1
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TOOLTIP PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Tooltip = function (element, options) {
+ this.type =
+ this.options =
+ this.enabled =
+ this.timeout =
+ this.hoverState =
+ this.$element = null
+
+ this.init('tooltip', element, options)
+ }
+
+ Tooltip.DEFAULTS = {
+ animation: true,
+ placement: 'top',
+ selector: false,
+ template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+ trigger: 'hover focus',
+ title: '',
+ delay: 0,
+ html: false,
+ container: false
+ }
+
+ Tooltip.prototype.init = function (type, element, options) {
+ this.enabled = true
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
+
+ var triggers = this.options.trigger.split(' ')
+
+ for (var i = triggers.length; i--;) {
+ var trigger = triggers[i]
+
+ if (trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+ }
+ }
+
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
+
+ Tooltip.prototype.getDefaults = function () {
+ return Tooltip.DEFAULTS
+ }
+
+ Tooltip.prototype.getOptions = function (options) {
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay,
+ hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ Tooltip.prototype.getDelegateOptions = function () {
+ var options = {}
+ var defaults = this.getDefaults()
+
+ this._options && $.each(this._options, function (key, value) {
+ if (defaults[key] != value) options[key] = value
+ })
+
+ return options
+ }
+
+ Tooltip.prototype.enter = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'in'
+
+ if (!self.options.delay || !self.options.delay.show) return self.show()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'in') self.show()
+ }, self.options.delay.show)
+ }
+
+ Tooltip.prototype.leave = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'out'
+
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'out') self.hide()
+ }, self.options.delay.hide)
+ }
+
+ Tooltip.prototype.show = function () {
+ var e = $.Event('show.bs.' + this.type)
+
+ if (this.hasContent() && this.enabled) {
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+ var that = this;
+
+ var $tip = this.tip()
+
+ this.setContent()
+
+ if (this.options.animation) $tip.addClass('fade')
+
+ var placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
+
+ var autoToken = /\s?auto?\s?/i
+ var autoPlace = autoToken.test(placement)
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+ $tip
+ .detach()
+ .css({ top: 0, left: 0, display: 'block' })
+ .addClass(placement)
+
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+ var pos = this.getPosition()
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (autoPlace) {
+ var $parent = this.$element.parent()
+
+ var orgPlacement = placement
+ var docScroll = document.documentElement.scrollTop || document.body.scrollTop
+ var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth()
+ var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
+ var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left
+
+ placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' :
+ placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' :
+ placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' :
+ placement
+
+ $tip
+ .removeClass(orgPlacement)
+ .addClass(placement)
+ }
+
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+ this.applyPlacement(calculatedOffset, placement)
+ this.hoverState = null
+
+ var complete = function() {
+ that.$element.trigger('shown.bs.' + that.type)
+ }
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one($.support.transition.end, complete)
+ .emulateTransitionEnd(150) :
+ complete()
+ }
+ }
+
+ Tooltip.prototype.applyPlacement = function (offset, placement) {
+ var replace
+ var $tip = this.tip()
+ var width = $tip[0].offsetWidth
+ var height = $tip[0].offsetHeight
+
+ // manually read margins because getBoundingClientRect includes difference
+ var marginTop = parseInt($tip.css('margin-top'), 10)
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+ // we must check for NaN for ie 8/9
+ if (isNaN(marginTop)) marginTop = 0
+ if (isNaN(marginLeft)) marginLeft = 0
+
+ offset.top = offset.top + marginTop
+ offset.left = offset.left + marginLeft
+
+ // $.fn.offset doesn't round pixel values
+ // so we use setOffset directly with our own function B-0
+ $.offset.setOffset($tip[0], $.extend({
+ using: function (props) {
+ $tip.css({
+ top: Math.round(props.top),
+ left: Math.round(props.left)
+ })
+ }
+ }, offset), 0)
+
+ $tip.addClass('in')
+
+ // check to see if placing tip in new offset caused the tip to resize itself
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (placement == 'top' && actualHeight != height) {
+ replace = true
+ offset.top = offset.top + height - actualHeight
+ }
+
+ if (/bottom|top/.test(placement)) {
+ var delta = 0
+
+ if (offset.left < 0) {
+ delta = offset.left * -2
+ offset.left = 0
+
+ $tip.offset(offset)
+
+ actualWidth = $tip[0].offsetWidth
+ actualHeight = $tip[0].offsetHeight
+ }
+
+ this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+ } else {
+ this.replaceArrow(actualHeight - height, actualHeight, 'top')
+ }
+
+ if (replace) $tip.offset(offset)
+ }
+
+ Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
+ this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
+ }
+
+ Tooltip.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+ $tip.removeClass('fade in top bottom left right')
+ }
+
+ Tooltip.prototype.hide = function () {
+ var that = this
+ var $tip = this.tip()
+ var e = $.Event('hide.bs.' + this.type)
+
+ function complete() {
+ if (that.hoverState != 'in') $tip.detach()
+ that.$element.trigger('hidden.bs.' + that.type)
+ }
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ $tip.removeClass('in')
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one($.support.transition.end, complete)
+ .emulateTransitionEnd(150) :
+ complete()
+
+ this.hoverState = null
+
+ return this
+ }
+
+ Tooltip.prototype.fixTitle = function () {
+ var $e = this.$element
+ if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+ }
+ }
+
+ Tooltip.prototype.hasContent = function () {
+ return this.getTitle()
+ }
+
+ Tooltip.prototype.getPosition = function () {
+ var el = this.$element[0]
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+ width: el.offsetWidth,
+ height: el.offsetHeight
+ }, this.$element.offset())
+ }
+
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+ }
+
+ Tooltip.prototype.getTitle = function () {
+ var title
+ var $e = this.$element
+ var o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ return title
+ }
+
+ Tooltip.prototype.tip = function () {
+ return this.$tip = this.$tip || $(this.options.template)
+ }
+
+ Tooltip.prototype.arrow = function () {
+ return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
+ }
+
+ Tooltip.prototype.validate = function () {
+ if (!this.$element[0].parentNode) {
+ this.hide()
+ this.$element = null
+ this.options = null
+ }
+ }
+
+ Tooltip.prototype.enable = function () {
+ this.enabled = true
+ }
+
+ Tooltip.prototype.disable = function () {
+ this.enabled = false
+ }
+
+ Tooltip.prototype.toggleEnabled = function () {
+ this.enabled = !this.enabled
+ }
+
+ Tooltip.prototype.toggle = function (e) {
+ var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+ }
+
+ Tooltip.prototype.destroy = function () {
+ clearTimeout(this.timeout)
+ this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+ }
+
+
+ // TOOLTIP PLUGIN DEFINITION
+ // =========================
+
+ var old = $.fn.tooltip
+
+ $.fn.tooltip = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tooltip')
+ var options = typeof option == 'object' && option
+
+ if (!data && option == 'destroy') return
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tooltip.Constructor = Tooltip
+
+
+ // TOOLTIP NO CONFLICT
+ // ===================
+
+ $.fn.tooltip.noConflict = function () {
+ $.fn.tooltip = old
+ return this
+ }
+
+}(jQuery);
diff --git a/bower_components/bootstrap/js/transition.js b/bower_components/bootstrap/js/transition.js
new file mode 100644
index 0000000..efa8c17
--- /dev/null
+++ b/bower_components/bootstrap/js/transition.js
@@ -0,0 +1,48 @@
+/* ========================================================================
+ * Bootstrap: transition.js v3.1.1
+ * http://getbootstrap.com/javascript/#transitions
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+ // ============================================================
+
+ function transitionEnd() {
+ var el = document.createElement('bootstrap')
+
+ var transEndEventNames = {
+ 'WebkitTransition' : 'webkitTransitionEnd',
+ 'MozTransition' : 'transitionend',
+ 'OTransition' : 'oTransitionEnd otransitionend',
+ 'transition' : 'transitionend'
+ }
+
+ for (var name in transEndEventNames) {
+ if (el.style[name] !== undefined) {
+ return { end: transEndEventNames[name] }
+ }
+ }
+
+ return false // explicit for ie8 ( ._.)
+ }
+
+ // http://blog.alexmaccaw.com/css-transitions
+ $.fn.emulateTransitionEnd = function (duration) {
+ var called = false, $el = this
+ $(this).one($.support.transition.end, function () { called = true })
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+ setTimeout(callback, duration)
+ return this
+ }
+
+ $(function () {
+ $.support.transition = transitionEnd()
+ })
+
+}(jQuery);
diff --git a/bower_components/bootstrap/less/alerts.less b/bower_components/bootstrap/less/alerts.less
new file mode 100644
index 0000000..3eab066
--- /dev/null
+++ b/bower_components/bootstrap/less/alerts.less
@@ -0,0 +1,67 @@
+//
+// Alerts
+// --------------------------------------------------
+
+
+// Base styles
+// -------------------------
+
+.alert {
+ padding: @alert-padding;
+ margin-bottom: @line-height-computed;
+ border: 1px solid transparent;
+ border-radius: @alert-border-radius;
+
+ // Headings for larger alerts
+ h4 {
+ margin-top: 0;
+ // Specified for the h4 to prevent conflicts of changing @headings-color
+ color: inherit;
+ }
+ // Provide class for links that match alerts
+ .alert-link {
+ font-weight: @alert-link-font-weight;
+ }
+
+ // Improve alignment and spacing of inner content
+ > p,
+ > ul {
+ margin-bottom: 0;
+ }
+ > p + p {
+ margin-top: 5px;
+ }
+}
+
+// Dismissable alerts
+//
+// Expand the right padding and account for the close button's positioning.
+
+.alert-dismissable {
+ padding-right: (@alert-padding + 20);
+
+ // Adjust close link position
+ .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ color: inherit;
+ }
+}
+
+// Alternate styles
+//
+// Generate contextual modifier classes for colorizing the alert.
+
+.alert-success {
+ .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);
+}
+.alert-info {
+ .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);
+}
+.alert-warning {
+ .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);
+}
+.alert-danger {
+ .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);
+}
diff --git a/bower_components/bootstrap/less/badges.less b/bower_components/bootstrap/less/badges.less
new file mode 100644
index 0000000..56828ca
--- /dev/null
+++ b/bower_components/bootstrap/less/badges.less
@@ -0,0 +1,55 @@
+//
+// Badges
+// --------------------------------------------------
+
+
+// Base classes
+.badge {
+ display: inline-block;
+ min-width: 10px;
+ padding: 3px 7px;
+ font-size: @font-size-small;
+ font-weight: @badge-font-weight;
+ color: @badge-color;
+ line-height: @badge-line-height;
+ vertical-align: baseline;
+ white-space: nowrap;
+ text-align: center;
+ background-color: @badge-bg;
+ border-radius: @badge-border-radius;
+
+ // Empty badges collapse automatically (not available in IE8)
+ &:empty {
+ display: none;
+ }
+
+ // Quick fix for badges in buttons
+ .btn & {
+ position: relative;
+ top: -1px;
+ }
+ .btn-xs & {
+ top: 0;
+ padding: 1px 5px;
+ }
+}
+
+// Hover state, but only for links
+a.badge {
+ &:hover,
+ &:focus {
+ color: @badge-link-hover-color;
+ text-decoration: none;
+ cursor: pointer;
+ }
+}
+
+// Account for counters in navs
+a.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+ color: @badge-active-color;
+ background-color: @badge-active-bg;
+}
+.nav-pills > li > a > .badge {
+ margin-left: 3px;
+}
diff --git a/bower_components/bootstrap/less/bootstrap.less b/bower_components/bootstrap/less/bootstrap.less
new file mode 100644
index 0000000..b368b87
--- /dev/null
+++ b/bower_components/bootstrap/less/bootstrap.less
@@ -0,0 +1,49 @@
+// Core variables and mixins
+@import "variables.less";
+@import "mixins.less";
+
+// Reset
+@import "normalize.less";
+@import "print.less";
+
+// Core CSS
+@import "scaffolding.less";
+@import "type.less";
+@import "code.less";
+@import "grid.less";
+@import "tables.less";
+@import "forms.less";
+@import "buttons.less";
+
+// Components
+@import "component-animations.less";
+@import "glyphicons.less";
+@import "dropdowns.less";
+@import "button-groups.less";
+@import "input-groups.less";
+@import "navs.less";
+@import "navbar.less";
+@import "breadcrumbs.less";
+@import "pagination.less";
+@import "pager.less";
+@import "labels.less";
+@import "badges.less";
+@import "jumbotron.less";
+@import "thumbnails.less";
+@import "alerts.less";
+@import "progress-bars.less";
+@import "media.less";
+@import "list-group.less";
+@import "panels.less";
+@import "wells.less";
+@import "close.less";
+
+// Components w/ JavaScript
+@import "modals.less";
+@import "tooltip.less";
+@import "popovers.less";
+@import "carousel.less";
+
+// Utility classes
+@import "utilities.less";
+@import "responsive-utilities.less";
diff --git a/bower_components/bootstrap/less/breadcrumbs.less b/bower_components/bootstrap/less/breadcrumbs.less
new file mode 100644
index 0000000..cb01d50
--- /dev/null
+++ b/bower_components/bootstrap/less/breadcrumbs.less
@@ -0,0 +1,26 @@
+//
+// Breadcrumbs
+// --------------------------------------------------
+
+
+.breadcrumb {
+ padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;
+ margin-bottom: @line-height-computed;
+ list-style: none;
+ background-color: @breadcrumb-bg;
+ border-radius: @border-radius-base;
+
+ > li {
+ display: inline-block;
+
+ + li:before {
+ content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space
+ padding: 0 5px;
+ color: @breadcrumb-color;
+ }
+ }
+
+ > .active {
+ color: @breadcrumb-active-color;
+ }
+}
diff --git a/bower_components/bootstrap/less/button-groups.less b/bower_components/bootstrap/less/button-groups.less
new file mode 100644
index 0000000..27eb796
--- /dev/null
+++ b/bower_components/bootstrap/less/button-groups.less
@@ -0,0 +1,226 @@
+//
+// Button groups
+// --------------------------------------------------
+
+// Make the div behave like a button
+.btn-group,
+.btn-group-vertical {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle; // match .btn alignment given font-size hack above
+ > .btn {
+ position: relative;
+ float: left;
+ // Bring the "active" button to the front
+ &:hover,
+ &:focus,
+ &:active,
+ &.active {
+ z-index: 2;
+ }
+ &:focus {
+ // Remove focus outline when dropdown JS adds it after closing the menu
+ outline: none;
+ }
+ }
+}
+
+// Prevent double borders when buttons are next to each other
+.btn-group {
+ .btn + .btn,
+ .btn + .btn-group,
+ .btn-group + .btn,
+ .btn-group + .btn-group {
+ margin-left: -1px;
+ }
+}
+
+// Optional: Group multiple button groups together for a toolbar
+.btn-toolbar {
+ margin-left: -5px; // Offset the first child's margin
+ &:extend(.clearfix all);
+
+ .btn-group,
+ .input-group {
+ float: left;
+ }
+ > .btn,
+ > .btn-group,
+ > .input-group {
+ margin-left: 5px;
+ }
+}
+
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+ border-radius: 0;
+}
+
+// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match
+.btn-group > .btn:first-child {
+ margin-left: 0;
+ &:not(:last-child):not(.dropdown-toggle) {
+ .border-right-radius(0);
+ }
+}
+// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+ .border-left-radius(0);
+}
+
+// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)
+.btn-group > .btn-group {
+ float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-radius: 0;
+}
+.btn-group > .btn-group:first-child {
+ > .btn:last-child,
+ > .dropdown-toggle {
+ .border-right-radius(0);
+ }
+}
+.btn-group > .btn-group:last-child > .btn:first-child {
+ .border-left-radius(0);
+}
+
+// On active and open, don't show outline
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+ outline: 0;
+}
+
+
+// Sizing
+//
+// Remix the default button sizing classes into new ones for easier manipulation.
+
+.btn-group-xs > .btn { &:extend(.btn-xs); }
+.btn-group-sm > .btn { &:extend(.btn-sm); }
+.btn-group-lg > .btn { &:extend(.btn-lg); }
+
+
+// Split button dropdowns
+// ----------------------
+
+// Give the line between buttons some depth
+.btn-group > .btn + .dropdown-toggle {
+ padding-left: 8px;
+ padding-right: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+ padding-left: 12px;
+ padding-right: 12px;
+}
+
+// The clickable button for toggling the menu
+// Remove the gradient and set the same inset shadow as the :active state
+.btn-group.open .dropdown-toggle {
+ .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
+
+ // Show no shadow for `.btn-link` since it has no other button styles.
+ &.btn-link {
+ .box-shadow(none);
+ }
+}
+
+
+// Reposition the caret
+.btn .caret {
+ margin-left: 0;
+}
+// Carets in other button sizes
+.btn-lg .caret {
+ border-width: @caret-width-large @caret-width-large 0;
+ border-bottom-width: 0;
+}
+// Upside down carets for .dropup
+.dropup .btn-lg .caret {
+ border-width: 0 @caret-width-large @caret-width-large;
+}
+
+
+// Vertical button groups
+// ----------------------
+
+.btn-group-vertical {
+ > .btn,
+ > .btn-group,
+ > .btn-group > .btn {
+ display: block;
+ float: none;
+ width: 100%;
+ max-width: 100%;
+ }
+
+ // Clear floats so dropdown menus can be properly placed
+ > .btn-group {
+ &:extend(.clearfix all);
+ > .btn {
+ float: none;
+ }
+ }
+
+ > .btn + .btn,
+ > .btn + .btn-group,
+ > .btn-group + .btn,
+ > .btn-group + .btn-group {
+ margin-top: -1px;
+ margin-left: 0;
+ }
+}
+
+.btn-group-vertical > .btn {
+ &:not(:first-child):not(:last-child) {
+ border-radius: 0;
+ }
+ &:first-child:not(:last-child) {
+ border-top-right-radius: @border-radius-base;
+ .border-bottom-radius(0);
+ }
+ &:last-child:not(:first-child) {
+ border-bottom-left-radius: @border-radius-base;
+ .border-top-radius(0);
+ }
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) {
+ > .btn:last-child,
+ > .dropdown-toggle {
+ .border-bottom-radius(0);
+ }
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+ .border-top-radius(0);
+}
+
+
+
+// Justified button groups
+// ----------------------
+
+.btn-group-justified {
+ display: table;
+ width: 100%;
+ table-layout: fixed;
+ border-collapse: separate;
+ > .btn,
+ > .btn-group {
+ float: none;
+ display: table-cell;
+ width: 1%;
+ }
+ > .btn-group .btn {
+ width: 100%;
+ }
+}
+
+
+// Checkbox and radio options
+[data-toggle="buttons"] > .btn > input[type="radio"],
+[data-toggle="buttons"] > .btn > input[type="checkbox"] {
+ display: none;
+}
diff --git a/bower_components/bootstrap/less/buttons.less b/bower_components/bootstrap/less/buttons.less
new file mode 100644
index 0000000..d4fc156
--- /dev/null
+++ b/bower_components/bootstrap/less/buttons.less
@@ -0,0 +1,159 @@
+//
+// Buttons
+// --------------------------------------------------
+
+
+// Base styles
+// --------------------------------------------------
+
+.btn {
+ display: inline-block;
+ margin-bottom: 0; // For input.btn
+ font-weight: @btn-font-weight;
+ text-align: center;
+ vertical-align: middle;
+ cursor: pointer;
+ background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
+ border: 1px solid transparent;
+ white-space: nowrap;
+ .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);
+ .user-select(none);
+
+ &,
+ &:active,
+ &.active {
+ &:focus {
+ .tab-focus();
+ }
+ }
+
+ &:hover,
+ &:focus {
+ color: @btn-default-color;
+ text-decoration: none;
+ }
+
+ &:active,
+ &.active {
+ outline: 0;
+ background-image: none;
+ .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
+ }
+
+ &.disabled,
+ &[disabled],
+ fieldset[disabled] & {
+ cursor: not-allowed;
+ pointer-events: none; // Future-proof disabling of clicks
+ .opacity(.65);
+ .box-shadow(none);
+ }
+}
+
+
+// Alternate buttons
+// --------------------------------------------------
+
+.btn-default {
+ .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);
+}
+.btn-primary {
+ .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);
+}
+// Success appears as green
+.btn-success {
+ .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);
+}
+// Info appears as blue-green
+.btn-info {
+ .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);
+}
+// Warning appears as orange
+.btn-warning {
+ .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);
+}
+// Danger and error appear as red
+.btn-danger {
+ .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);
+}
+
+
+// Link buttons
+// -------------------------
+
+// Make a button look and behave like a link
+.btn-link {
+ color: @link-color;
+ font-weight: normal;
+ cursor: pointer;
+ border-radius: 0;
+
+ &,
+ &:active,
+ &[disabled],
+ fieldset[disabled] & {
+ background-color: transparent;
+ .box-shadow(none);
+ }
+ &,
+ &:hover,
+ &:focus,
+ &:active {
+ border-color: transparent;
+ }
+ &:hover,
+ &:focus {
+ color: @link-hover-color;
+ text-decoration: underline;
+ background-color: transparent;
+ }
+ &[disabled],
+ fieldset[disabled] & {
+ &:hover,
+ &:focus {
+ color: @btn-link-disabled-color;
+ text-decoration: none;
+ }
+ }
+}
+
+
+// Button Sizes
+// --------------------------------------------------
+
+.btn-lg {
+ // line-height: ensure even-numbered height of button next to large input
+ .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);
+}
+.btn-sm {
+ // line-height: ensure proper height of button next to small input
+ .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);
+}
+.btn-xs {
+ .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);
+}
+
+
+// Block button
+// --------------------------------------------------
+
+.btn-block {
+ display: block;
+ width: 100%;
+ padding-left: 0;
+ padding-right: 0;
+}
+
+// Vertically space out multiple block buttons
+.btn-block + .btn-block {
+ margin-top: 5px;
+}
+
+// Specificity overrides
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+ &.btn-block {
+ width: 100%;
+ }
+}
diff --git a/bower_components/bootstrap/less/carousel.less b/bower_components/bootstrap/less/carousel.less
new file mode 100644
index 0000000..e3fb8a2
--- /dev/null
+++ b/bower_components/bootstrap/less/carousel.less
@@ -0,0 +1,232 @@
+//
+// Carousel
+// --------------------------------------------------
+
+
+// Wrapper for the slide container and indicators
+.carousel {
+ position: relative;
+}
+
+.carousel-inner {
+ position: relative;
+ overflow: hidden;
+ width: 100%;
+
+ > .item {
+ display: none;
+ position: relative;
+ .transition(.6s ease-in-out left);
+
+ // Account for jankitude on images
+ > img,
+ > a > img {
+ &:extend(.img-responsive);
+ line-height: 1;
+ }
+ }
+
+ > .active,
+ > .next,
+ > .prev { display: block; }
+
+ > .active {
+ left: 0;
+ }
+
+ > .next,
+ > .prev {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ }
+
+ > .next {
+ left: 100%;
+ }
+ > .prev {
+ left: -100%;
+ }
+ > .next.left,
+ > .prev.right {
+ left: 0;
+ }
+
+ > .active.left {
+ left: -100%;
+ }
+ > .active.right {
+ left: 100%;
+ }
+
+}
+
+// Left/right controls for nav
+// ---------------------------
+
+.carousel-control {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ width: @carousel-control-width;
+ .opacity(@carousel-control-opacity);
+ font-size: @carousel-control-font-size;
+ color: @carousel-control-color;
+ text-align: center;
+ text-shadow: @carousel-text-shadow;
+ // We can't have this transition here because WebKit cancels the carousel
+ // animation if you trip this while in the middle of another animation.
+
+ // Set gradients for backgrounds
+ &.left {
+ #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));
+ }
+ &.right {
+ left: auto;
+ right: 0;
+ #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));
+ }
+
+ // Hover/focus state
+ &:hover,
+ &:focus {
+ outline: none;
+ color: @carousel-control-color;
+ text-decoration: none;
+ .opacity(.9);
+ }
+
+ // Toggles
+ .icon-prev,
+ .icon-next,
+ .glyphicon-chevron-left,
+ .glyphicon-chevron-right {
+ position: absolute;
+ top: 50%;
+ z-index: 5;
+ display: inline-block;
+ }
+ .icon-prev,
+ .glyphicon-chevron-left {
+ left: 50%;
+ }
+ .icon-next,
+ .glyphicon-chevron-right {
+ right: 50%;
+ }
+ .icon-prev,
+ .icon-next {
+ width: 20px;
+ height: 20px;
+ margin-top: -10px;
+ margin-left: -10px;
+ font-family: serif;
+ }
+
+ .icon-prev {
+ &:before {
+ content: '\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)
+ }
+ }
+ .icon-next {
+ &:before {
+ content: '\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)
+ }
+ }
+}
+
+// Optional indicator pips
+//
+// Add an unordered list with the following class and add a list item for each
+// slide your carousel holds.
+
+.carousel-indicators {
+ position: absolute;
+ bottom: 10px;
+ left: 50%;
+ z-index: 15;
+ width: 60%;
+ margin-left: -30%;
+ padding-left: 0;
+ list-style: none;
+ text-align: center;
+
+ li {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ margin: 1px;
+ text-indent: -999px;
+ border: 1px solid @carousel-indicator-border-color;
+ border-radius: 10px;
+ cursor: pointer;
+
+ // IE8-9 hack for event handling
+ //
+ // Internet Explorer 8-9 does not support clicks on elements without a set
+ // `background-color`. We cannot use `filter` since that's not viewed as a
+ // background color by the browser. Thus, a hack is needed.
+ //
+ // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we
+ // set alpha transparency for the best results possible.
+ background-color: #000 \9; // IE8
+ background-color: rgba(0,0,0,0); // IE9
+ }
+ .active {
+ margin: 0;
+ width: 12px;
+ height: 12px;
+ background-color: @carousel-indicator-active-bg;
+ }
+}
+
+// Optional captions
+// -----------------------------
+// Hidden by default for smaller viewports
+.carousel-caption {
+ position: absolute;
+ left: 15%;
+ right: 15%;
+ bottom: 20px;
+ z-index: 10;
+ padding-top: 20px;
+ padding-bottom: 20px;
+ color: @carousel-caption-color;
+ text-align: center;
+ text-shadow: @carousel-text-shadow;
+ & .btn {
+ text-shadow: none; // No shadow for button elements in carousel-caption
+ }
+}
+
+
+// Scale up controls for tablets and up
+@media screen and (min-width: @screen-sm-min) {
+
+ // Scale up the controls a smidge
+ .carousel-control {
+ .glyphicon-chevron-left,
+ .glyphicon-chevron-right,
+ .icon-prev,
+ .icon-next {
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ margin-left: -15px;
+ font-size: 30px;
+ }
+ }
+
+ // Show and left align the captions
+ .carousel-caption {
+ left: 20%;
+ right: 20%;
+ padding-bottom: 30px;
+ }
+
+ // Move up the indicators
+ .carousel-indicators {
+ bottom: 20px;
+ }
+}
diff --git a/bower_components/bootstrap/less/close.less b/bower_components/bootstrap/less/close.less
new file mode 100644
index 0000000..9b4e74f
--- /dev/null
+++ b/bower_components/bootstrap/less/close.less
@@ -0,0 +1,33 @@
+//
+// Close icons
+// --------------------------------------------------
+
+
+.close {
+ float: right;
+ font-size: (@font-size-base * 1.5);
+ font-weight: @close-font-weight;
+ line-height: 1;
+ color: @close-color;
+ text-shadow: @close-text-shadow;
+ .opacity(.2);
+
+ &:hover,
+ &:focus {
+ color: @close-color;
+ text-decoration: none;
+ cursor: pointer;
+ .opacity(.5);
+ }
+
+ // Additional properties for button version
+ // iOS requires the button element instead of an anchor tag.
+ // If you want the anchor version, it requires `href="#"`.
+ button& {
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+ -webkit-appearance: none;
+ }
+}
diff --git a/bower_components/bootstrap/less/code.less b/bower_components/bootstrap/less/code.less
new file mode 100644
index 0000000..3eed26c
--- /dev/null
+++ b/bower_components/bootstrap/less/code.less
@@ -0,0 +1,63 @@
+//
+// Code (inline and block)
+// --------------------------------------------------
+
+
+// Inline and block code styles
+code,
+kbd,
+pre,
+samp {
+ font-family: @font-family-monospace;
+}
+
+// Inline code
+code {
+ padding: 2px 4px;
+ font-size: 90%;
+ color: @code-color;
+ background-color: @code-bg;
+ white-space: nowrap;
+ border-radius: @border-radius-base;
+}
+
+// User input typically entered via keyboard
+kbd {
+ padding: 2px 4px;
+ font-size: 90%;
+ color: @kbd-color;
+ background-color: @kbd-bg;
+ border-radius: @border-radius-small;
+ box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);
+}
+
+// Blocks of code
+pre {
+ display: block;
+ padding: ((@line-height-computed - 1) / 2);
+ margin: 0 0 (@line-height-computed / 2);
+ font-size: (@font-size-base - 1); // 14px to 13px
+ line-height: @line-height-base;
+ word-break: break-all;
+ word-wrap: break-word;
+ color: @pre-color;
+ background-color: @pre-bg;
+ border: 1px solid @pre-border-color;
+ border-radius: @border-radius-base;
+
+ // Account for some code outputs that place code tags in pre tags
+ code {
+ padding: 0;
+ font-size: inherit;
+ color: inherit;
+ white-space: pre-wrap;
+ background-color: transparent;
+ border-radius: 0;
+ }
+}
+
+// Enable scrollable blocks of code
+.pre-scrollable {
+ max-height: @pre-scrollable-max-height;
+ overflow-y: scroll;
+}
diff --git a/bower_components/bootstrap/less/component-animations.less b/bower_components/bootstrap/less/component-animations.less
new file mode 100644
index 0000000..1efe45e
--- /dev/null
+++ b/bower_components/bootstrap/less/component-animations.less
@@ -0,0 +1,29 @@
+//
+// Component animations
+// --------------------------------------------------
+
+// Heads up!
+//
+// We don't use the `.opacity()` mixin here since it causes a bug with text
+// fields in IE7-8. Source: https://github.com/twitter/bootstrap/pull/3552.
+
+.fade {
+ opacity: 0;
+ .transition(opacity .15s linear);
+ &.in {
+ opacity: 1;
+ }
+}
+
+.collapse {
+ display: none;
+ &.in {
+ display: block;
+ }
+}
+.collapsing {
+ position: relative;
+ height: 0;
+ overflow: hidden;
+ .transition(height .35s ease);
+}
diff --git a/bower_components/bootstrap/less/dropdowns.less b/bower_components/bootstrap/less/dropdowns.less
new file mode 100644
index 0000000..f165165
--- /dev/null
+++ b/bower_components/bootstrap/less/dropdowns.less
@@ -0,0 +1,213 @@
+//
+// Dropdown menus
+// --------------------------------------------------
+
+
+// Dropdown arrow/caret
+.caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 2px;
+ vertical-align: middle;
+ border-top: @caret-width-base solid;
+ border-right: @caret-width-base solid transparent;
+ border-left: @caret-width-base solid transparent;
+}
+
+// The dropdown wrapper (div)
+.dropdown {
+ position: relative;
+}
+
+// Prevent the focus on the dropdown toggle when closing dropdowns
+.dropdown-toggle:focus {
+ outline: 0;
+}
+
+// The dropdown menu (ul)
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: @zindex-dropdown;
+ display: none; // none by default, but block on "open" of the menu
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 0 0; // override default ul
+ list-style: none;
+ font-size: @font-size-base;
+ background-color: @dropdown-bg;
+ border: 1px solid @dropdown-fallback-border; // IE8 fallback
+ border: 1px solid @dropdown-border;
+ border-radius: @border-radius-base;
+ .box-shadow(0 6px 12px rgba(0,0,0,.175));
+ background-clip: padding-box;
+
+ // Aligns the dropdown menu to right
+ //
+ // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`
+ &.pull-right {
+ right: 0;
+ left: auto;
+ }
+
+ // Dividers (basically an hr) within the dropdown
+ .divider {
+ .nav-divider(@dropdown-divider-bg);
+ }
+
+ // Links within the dropdown menu
+ > li > a {
+ display: block;
+ padding: 3px 20px;
+ clear: both;
+ font-weight: normal;
+ line-height: @line-height-base;
+ color: @dropdown-link-color;
+ white-space: nowrap; // prevent links from randomly breaking onto new lines
+ }
+}
+
+// Hover/Focus state
+.dropdown-menu > li > a {
+ &:hover,
+ &:focus {
+ text-decoration: none;
+ color: @dropdown-link-hover-color;
+ background-color: @dropdown-link-hover-bg;
+ }
+}
+
+// Active state
+.dropdown-menu > .active > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @dropdown-link-active-color;
+ text-decoration: none;
+ outline: 0;
+ background-color: @dropdown-link-active-bg;
+ }
+}
+
+// Disabled state
+//
+// Gray out text and ensure the hover/focus state remains gray
+
+.dropdown-menu > .disabled > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @dropdown-link-disabled-color;
+ }
+}
+// Nuke hover/focus effects
+.dropdown-menu > .disabled > a {
+ &:hover,
+ &:focus {
+ text-decoration: none;
+ background-color: transparent;
+ background-image: none; // Remove CSS gradient
+ .reset-filter();
+ cursor: not-allowed;
+ }
+}
+
+// Open state for the dropdown
+.open {
+ // Show the menu
+ > .dropdown-menu {
+ display: block;
+ }
+
+ // Remove the outline when :focus is triggered
+ > a {
+ outline: 0;
+ }
+}
+
+// Menu positioning
+//
+// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown
+// menu with the parent.
+.dropdown-menu-right {
+ left: auto; // Reset the default from `.dropdown-menu`
+ right: 0;
+}
+// With v3, we enabled auto-flipping if you have a dropdown within a right
+// aligned nav component. To enable the undoing of that, we provide an override
+// to restore the default dropdown menu alignment.
+//
+// This is only for left-aligning a dropdown menu within a `.navbar-right` or
+// `.pull-right` nav component.
+.dropdown-menu-left {
+ left: 0;
+ right: auto;
+}
+
+// Dropdown section headers
+.dropdown-header {
+ display: block;
+ padding: 3px 20px;
+ font-size: @font-size-small;
+ line-height: @line-height-base;
+ color: @dropdown-header-color;
+}
+
+// Backdrop to catch body clicks on mobile, etc.
+.dropdown-backdrop {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ top: 0;
+ z-index: (@zindex-dropdown - 10);
+}
+
+// Right aligned dropdowns
+.pull-right > .dropdown-menu {
+ right: 0;
+ left: auto;
+}
+
+// Allow for dropdowns to go bottom up (aka, dropup-menu)
+//
+// Just add .dropup after the standard .dropdown class and you're set, bro.
+// TODO: abstract this so that the navbar fixed styles are not placed here?
+
+.dropup,
+.navbar-fixed-bottom .dropdown {
+ // Reverse the caret
+ .caret {
+ border-top: 0;
+ border-bottom: @caret-width-base solid;
+ content: "";
+ }
+ // Different positioning for bottom up menu
+ .dropdown-menu {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 1px;
+ }
+}
+
+
+// Component alignment
+//
+// Reiterate per navbar.less and the modified component alignment there.
+
+@media (min-width: @grid-float-breakpoint) {
+ .navbar-right {
+ .dropdown-menu {
+ .dropdown-menu-right();
+ }
+ // Necessary for overrides of the default right aligned menu.
+ // Will remove come v4 in all likelihood.
+ .dropdown-menu-left {
+ .dropdown-menu-left();
+ }
+ }
+}
+
diff --git a/bower_components/bootstrap/less/forms.less b/bower_components/bootstrap/less/forms.less
new file mode 100644
index 0000000..f607b85
--- /dev/null
+++ b/bower_components/bootstrap/less/forms.less
@@ -0,0 +1,438 @@
+//
+// Forms
+// --------------------------------------------------
+
+
+// Normalize non-controls
+//
+// Restyle and baseline non-control form elements.
+
+fieldset {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ // Chrome and Firefox set a `min-width: -webkit-min-content;` on fieldsets,
+ // so we reset that to ensure it behaves more like a standard block element.
+ // See https://github.com/twbs/bootstrap/issues/12359.
+ min-width: 0;
+}
+
+legend {
+ display: block;
+ width: 100%;
+ padding: 0;
+ margin-bottom: @line-height-computed;
+ font-size: (@font-size-base * 1.5);
+ line-height: inherit;
+ color: @legend-color;
+ border: 0;
+ border-bottom: 1px solid @legend-border-color;
+}
+
+label {
+ display: inline-block;
+ margin-bottom: 5px;
+ font-weight: bold;
+}
+
+
+// Normalize form controls
+//
+// While most of our form styles require extra classes, some basic normalization
+// is required to ensure optimum display with or without those classes to better
+// address browser inconsistencies.
+
+// Override content-box in Normalize (* isn't specific enough)
+input[type="search"] {
+ .box-sizing(border-box);
+}
+
+// Position radios and checkboxes better
+input[type="radio"],
+input[type="checkbox"] {
+ margin: 4px 0 0;
+ margin-top: 1px \9; /* IE8-9 */
+ line-height: normal;
+}
+
+// Set the height of file controls to match text inputs
+input[type="file"] {
+ display: block;
+}
+
+// Make range inputs behave like textual form controls
+input[type="range"] {
+ display: block;
+ width: 100%;
+}
+
+// Make multiple select elements height not fixed
+select[multiple],
+select[size] {
+ height: auto;
+}
+
+// Focus for file, radio, and checkbox
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+ .tab-focus();
+}
+
+// Adjust output element
+output {
+ display: block;
+ padding-top: (@padding-base-vertical + 1);
+ font-size: @font-size-base;
+ line-height: @line-height-base;
+ color: @input-color;
+}
+
+
+// Common form controls
+//
+// Shared size and type resets for form controls. Apply `.form-control` to any
+// of the following form controls:
+//
+// select
+// textarea
+// input[type="text"]
+// input[type="password"]
+// input[type="datetime"]
+// input[type="datetime-local"]
+// input[type="date"]
+// input[type="month"]
+// input[type="time"]
+// input[type="week"]
+// input[type="number"]
+// input[type="email"]
+// input[type="url"]
+// input[type="search"]
+// input[type="tel"]
+// input[type="color"]
+
+.form-control {
+ display: block;
+ width: 100%;
+ height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)
+ padding: @padding-base-vertical @padding-base-horizontal;
+ font-size: @font-size-base;
+ line-height: @line-height-base;
+ color: @input-color;
+ background-color: @input-bg;
+ background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
+ border: 1px solid @input-border;
+ border-radius: @input-border-radius;
+ .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));
+ .transition(~"border-color ease-in-out .15s, box-shadow ease-in-out .15s");
+
+ // Customize the `:focus` state to imitate native WebKit styles.
+ .form-control-focus();
+
+ // Placeholder
+ .placeholder();
+
+ // Disabled and read-only inputs
+ //
+ // HTML5 says that controls under a fieldset > legend:first-child won't be
+ // disabled if the fieldset is disabled. Due to implementation difficulty, we
+ // don't honor that edge case; we style them as disabled anyway.
+ &[disabled],
+ &[readonly],
+ fieldset[disabled] & {
+ cursor: not-allowed;
+ background-color: @input-bg-disabled;
+ opacity: 1; // iOS fix for unreadable disabled content
+ }
+
+ // Reset height for `textarea`s
+ textarea& {
+ height: auto;
+ }
+}
+
+
+// Search inputs in iOS
+//
+// This overrides the extra rounded corners on search inputs in iOS so that our
+// `.form-control` class can properly style them. Note that this cannot simply
+// be added to `.form-control` as it's not specific enough. For details, see
+// https://github.com/twbs/bootstrap/issues/11586.
+
+input[type="search"] {
+ -webkit-appearance: none;
+}
+
+
+// Special styles for iOS date input
+//
+// In Mobile Safari, date inputs require a pixel line-height that matches the
+// given height of the input.
+
+input[type="date"] {
+ line-height: @input-height-base;
+}
+
+
+// Form groups
+//
+// Designed to help with the organization and spacing of vertical forms. For
+// horizontal forms, use the predefined grid classes.
+
+.form-group {
+ margin-bottom: 15px;
+}
+
+
+// Checkboxes and radios
+//
+// Indent the labels to position radios/checkboxes as hanging controls.
+
+.radio,
+.checkbox {
+ display: block;
+ min-height: @line-height-computed; // clear the floating input if there is no label text
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding-left: 20px;
+ label {
+ display: inline;
+ font-weight: normal;
+ cursor: pointer;
+ }
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+ float: left;
+ margin-left: -20px;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+ margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing
+}
+
+// Radios and checkboxes on same line
+.radio-inline,
+.checkbox-inline {
+ display: inline-block;
+ padding-left: 20px;
+ margin-bottom: 0;
+ vertical-align: middle;
+ font-weight: normal;
+ cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+ margin-top: 0;
+ margin-left: 10px; // space out consecutive inline controls
+}
+
+// Apply same disabled cursor tweak as for inputs
+//
+// Note: Neither radios nor checkboxes can be readonly.
+input[type="radio"],
+input[type="checkbox"],
+.radio,
+.radio-inline,
+.checkbox,
+.checkbox-inline {
+ &[disabled],
+ fieldset[disabled] & {
+ cursor: not-allowed;
+ }
+}
+
+
+// Form control sizing
+//
+// Build on `.form-control` with modifier classes to decrease or increase the
+// height and font-size of form controls.
+
+.input-sm {
+ .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);
+}
+
+.input-lg {
+ .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);
+}
+
+
+// Form control feedback states
+//
+// Apply contextual and semantic states to individual form controls.
+
+.has-feedback {
+ // Enable absolute positioning
+ position: relative;
+
+ // Ensure icons don't overlap text
+ .form-control {
+ padding-right: (@input-height-base * 1.25);
+ }
+
+ // Feedback icon (requires .glyphicon classes)
+ .form-control-feedback {
+ position: absolute;
+ top: (@line-height-computed + 5); // Height of the `label` and its margin
+ right: 0;
+ display: block;
+ width: @input-height-base;
+ height: @input-height-base;
+ line-height: @input-height-base;
+ text-align: center;
+ }
+}
+
+// Feedback states
+.has-success {
+ .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);
+}
+.has-warning {
+ .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);
+}
+.has-error {
+ .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);
+}
+
+
+// Static form control text
+//
+// Apply class to a `p` element to make any string of text align with labels in
+// a horizontal form layout.
+
+.form-control-static {
+ margin-bottom: 0; // Remove default margin from `p`
+}
+
+
+// Help text
+//
+// Apply to any element you wish to create light text for placement immediately
+// below a form control. Use for general help, formatting, or instructional text.
+
+.help-block {
+ display: block; // account for any element using help-block
+ margin-top: 5px;
+ margin-bottom: 10px;
+ color: lighten(@text-color, 25%); // lighten the text some for contrast
+}
+
+
+
+// Inline forms
+//
+// Make forms appear inline(-block) by adding the `.form-inline` class. Inline
+// forms begin stacked on extra small (mobile) devices and then go inline when
+// viewports reach <768px.
+//
+// Requires wrapping inputs and labels with `.form-group` for proper display of
+// default HTML form controls and our custom form controls (e.g., input groups).
+//
+// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.
+
+.form-inline {
+
+ // Kick in the inline
+ @media (min-width: @screen-sm-min) {
+ // Inline-block all the things for "inline"
+ .form-group {
+ display: inline-block;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+
+ // In navbar-form, allow folks to *not* use `.form-group`
+ .form-control {
+ display: inline-block;
+ width: auto; // Prevent labels from stacking above inputs in `.form-group`
+ vertical-align: middle;
+ }
+ // Input groups need that 100% width though
+ .input-group > .form-control {
+ width: 100%;
+ }
+
+ .control-label {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+
+ // Remove default margin on radios/checkboxes that were used for stacking, and
+ // then undo the floating of radios and checkboxes to match (which also avoids
+ // a bug in WebKit: https://github.com/twbs/bootstrap/issues/1969).
+ .radio,
+ .checkbox {
+ display: inline-block;
+ margin-top: 0;
+ margin-bottom: 0;
+ padding-left: 0;
+ vertical-align: middle;
+ }
+ .radio input[type="radio"],
+ .checkbox input[type="checkbox"] {
+ float: none;
+ margin-left: 0;
+ }
+
+ // Validation states
+ //
+ // Reposition the icon because it's now within a grid column and columns have
+ // `position: relative;` on them. Also accounts for the grid gutter padding.
+ .has-feedback .form-control-feedback {
+ top: 0;
+ }
+ }
+}
+
+
+// Horizontal forms
+//
+// Horizontal forms are built on grid classes and allow you to create forms with
+// labels on the left and inputs on the right.
+
+.form-horizontal {
+
+ // Consistent vertical alignment of labels, radios, and checkboxes
+ .control-label,
+ .radio,
+ .checkbox,
+ .radio-inline,
+ .checkbox-inline {
+ margin-top: 0;
+ margin-bottom: 0;
+ padding-top: (@padding-base-vertical + 1); // Default padding plus a border
+ }
+ // Account for padding we're adding to ensure the alignment and of help text
+ // and other content below items
+ .radio,
+ .checkbox {
+ min-height: (@line-height-computed + (@padding-base-vertical + 1));
+ }
+
+ // Make form groups behave like rows
+ .form-group {
+ .make-row();
+ }
+
+ .form-control-static {
+ padding-top: (@padding-base-vertical + 1);
+ }
+
+ // Only right align form labels here when the columns stop stacking
+ @media (min-width: @screen-sm-min) {
+ .control-label {
+ text-align: right;
+ }
+ }
+
+ // Validation states
+ //
+ // Reposition the icon because it's now within a grid column and columns have
+ // `position: relative;` on them. Also accounts for the grid gutter padding.
+ .has-feedback .form-control-feedback {
+ top: 0;
+ right: (@grid-gutter-width / 2);
+ }
+}
diff --git a/bower_components/bootstrap/less/glyphicons.less b/bower_components/bootstrap/less/glyphicons.less
new file mode 100644
index 0000000..789c5e7
--- /dev/null
+++ b/bower_components/bootstrap/less/glyphicons.less
@@ -0,0 +1,233 @@
+//
+// Glyphicons for Bootstrap
+//
+// Since icons are fonts, they can be placed anywhere text is placed and are
+// thus automatically sized to match the surrounding child. To use, create an
+// inline element with the appropriate classes, like so:
+//
+// <a href="#"><span class="glyphicon glyphicon-star"></span> Star</a>
+
+// Import the fonts
+@font-face {
+ font-family: 'Glyphicons Halflings';
+ src: ~"url('@{icon-font-path}@{icon-font-name}.eot')";
+ src: ~"url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype')",
+ ~"url('@{icon-font-path}@{icon-font-name}.woff') format('woff')",
+ ~"url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype')",
+ ~"url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg')";
+}
+
+// Catchall baseclass
+.glyphicon {
+ position: relative;
+ top: 1px;
+ display: inline-block;
+ font-family: 'Glyphicons Halflings';
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+// Individual icons
+.glyphicon-asterisk { &:before { content: "\2a"; } }
+.glyphicon-plus { &:before { content: "\2b"; } }
+.glyphicon-euro { &:before { content: "\20ac"; } }
+.glyphicon-minus { &:before { content: "\2212"; } }
+.glyphicon-cloud { &:before { content: "\2601"; } }
+.glyphicon-envelope { &:before { content: "\2709"; } }
+.glyphicon-pencil { &:before { content: "\270f"; } }
+.glyphicon-glass { &:before { content: "\e001"; } }
+.glyphicon-music { &:before { content: "\e002"; } }
+.glyphicon-search { &:before { content: "\e003"; } }
+.glyphicon-heart { &:before { content: "\e005"; } }
+.glyphicon-star { &:before { content: "\e006"; } }
+.glyphicon-star-empty { &:before { content: "\e007"; } }
+.glyphicon-user { &:before { content: "\e008"; } }
+.glyphicon-film { &:before { content: "\e009"; } }
+.glyphicon-th-large { &:before { content: "\e010"; } }
+.glyphicon-th { &:before { content: "\e011"; } }
+.glyphicon-th-list { &:before { content: "\e012"; } }
+.glyphicon-ok { &:before { content: "\e013"; } }
+.glyphicon-remove { &:before { content: "\e014"; } }
+.glyphicon-zoom-in { &:before { content: "\e015"; } }
+.glyphicon-zoom-out { &:before { content: "\e016"; } }
+.glyphicon-off { &:before { content: "\e017"; } }
+.glyphicon-signal { &:before { content: "\e018"; } }
+.glyphicon-cog { &:before { content: "\e019"; } }
+.glyphicon-trash { &:before { content: "\e020"; } }
+.glyphicon-home { &:before { content: "\e021"; } }
+.glyphicon-file { &:before { content: "\e022"; } }
+.glyphicon-time { &:before { content: "\e023"; } }
+.glyphicon-road { &:before { content: "\e024"; } }
+.glyphicon-download-alt { &:before { content: "\e025"; } }
+.glyphicon-download { &:before { content: "\e026"; } }
+.glyphicon-upload { &:before { content: "\e027"; } }
+.glyphicon-inbox { &:before { content: "\e028"; } }
+.glyphicon-play-circle { &:before { content: "\e029"; } }
+.glyphicon-repeat { &:before { content: "\e030"; } }
+.glyphicon-refresh { &:before { content: "\e031"; } }
+.glyphicon-list-alt { &:before { content: "\e032"; } }
+.glyphicon-lock { &:before { content: "\e033"; } }
+.glyphicon-flag { &:before { content: "\e034"; } }
+.glyphicon-headphones { &:before { content: "\e035"; } }
+.glyphicon-volume-off { &:before { content: "\e036"; } }
+.glyphicon-volume-down { &:before { content: "\e037"; } }
+.glyphicon-volume-up { &:before { content: "\e038"; } }
+.glyphicon-qrcode { &:before { content: "\e039"; } }
+.glyphicon-barcode { &:before { content: "\e040"; } }
+.glyphicon-tag { &:before { content: "\e041"; } }
+.glyphicon-tags { &:before { content: "\e042"; } }
+.glyphicon-book { &:before { content: "\e043"; } }
+.glyphicon-bookmark { &:before { content: "\e044"; } }
+.glyphicon-print { &:before { content: "\e045"; } }
+.glyphicon-camera { &:before { content: "\e046"; } }
+.glyphicon-font { &:before { content: "\e047"; } }
+.glyphicon-bold { &:before { content: "\e048"; } }
+.glyphicon-italic { &:before { content: "\e049"; } }
+.glyphicon-text-height { &:before { content: "\e050"; } }
+.glyphicon-text-width { &:before { content: "\e051"; } }
+.glyphicon-align-left { &:before { content: "\e052"; } }
+.glyphicon-align-center { &:before { content: "\e053"; } }
+.glyphicon-align-right { &:before { content: "\e054"; } }
+.glyphicon-align-justify { &:before { content: "\e055"; } }
+.glyphicon-list { &:before { content: "\e056"; } }
+.glyphicon-indent-left { &:before { content: "\e057"; } }
+.glyphicon-indent-right { &:before { content: "\e058"; } }
+.glyphicon-facetime-video { &:before { content: "\e059"; } }
+.glyphicon-picture { &:before { content: "\e060"; } }
+.glyphicon-map-marker { &:before { content: "\e062"; } }
+.glyphicon-adjust { &:before { content: "\e063"; } }
+.glyphicon-tint { &:before { content: "\e064"; } }
+.glyphicon-edit { &:before { content: "\e065"; } }
+.glyphicon-share { &:before { content: "\e066"; } }
+.glyphicon-check { &:before { content: "\e067"; } }
+.glyphicon-move { &:before { content: "\e068"; } }
+.glyphicon-step-backward { &:before { content: "\e069"; } }
+.glyphicon-fast-backward { &:before { content: "\e070"; } }
+.glyphicon-backward { &:before { content: "\e071"; } }
+.glyphicon-play { &:before { content: "\e072"; } }
+.glyphicon-pause { &:before { content: "\e073"; } }
+.glyphicon-stop { &:before { content: "\e074"; } }
+.glyphicon-forward { &:before { content: "\e075"; } }
+.glyphicon-fast-forward { &:before { content: "\e076"; } }
+.glyphicon-step-forward { &:before { content: "\e077"; } }
+.glyphicon-eject { &:before { content: "\e078"; } }
+.glyphicon-chevron-left { &:before { content: "\e079"; } }
+.glyphicon-chevron-right { &:before { content: "\e080"; } }
+.glyphicon-plus-sign { &:before { content: "\e081"; } }
+.glyphicon-minus-sign { &:before { content: "\e082"; } }
+.glyphicon-remove-sign { &:before { content: "\e083"; } }
+.glyphicon-ok-sign { &:before { content: "\e084"; } }
+.glyphicon-question-sign { &:before { content: "\e085"; } }
+.glyphicon-info-sign { &:before { content: "\e086"; } }
+.glyphicon-screenshot { &:before { content: "\e087"; } }
+.glyphicon-remove-circle { &:before { content: "\e088"; } }
+.glyphicon-ok-circle { &:before { content: "\e089"; } }
+.glyphicon-ban-circle { &:before { content: "\e090"; } }
+.glyphicon-arrow-left { &:before { content: "\e091"; } }
+.glyphicon-arrow-right { &:before { content: "\e092"; } }
+.glyphicon-arrow-up { &:before { content: "\e093"; } }
+.glyphicon-arrow-down { &:before { content: "\e094"; } }
+.glyphicon-share-alt { &:before { content: "\e095"; } }
+.glyphicon-resize-full { &:before { content: "\e096"; } }
+.glyphicon-resize-small { &:before { content: "\e097"; } }
+.glyphicon-exclamation-sign { &:before { content: "\e101"; } }
+.glyphicon-gift { &:before { content: "\e102"; } }
+.glyphicon-leaf { &:before { content: "\e103"; } }
+.glyphicon-fire { &:before { content: "\e104"; } }
+.glyphicon-eye-open { &:before { content: "\e105"; } }
+.glyphicon-eye-close { &:before { content: "\e106"; } }
+.glyphicon-warning-sign { &:before { content: "\e107"; } }
+.glyphicon-plane { &:before { content: "\e108"; } }
+.glyphicon-calendar { &:before { content: "\e109"; } }
+.glyphicon-random { &:before { content: "\e110"; } }
+.glyphicon-comment { &:before { content: "\e111"; } }
+.glyphicon-magnet { &:before { content: "\e112"; } }
+.glyphicon-chevron-up { &:before { content: "\e113"; } }
+.glyphicon-chevron-down { &:before { content: "\e114"; } }
+.glyphicon-retweet { &:before { content: "\e115"; } }
+.glyphicon-shopping-cart { &:before { content: "\e116"; } }
+.glyphicon-folder-close { &:before { content: "\e117"; } }
+.glyphicon-folder-open { &:before { content: "\e118"; } }
+.glyphicon-resize-vertical { &:before { content: "\e119"; } }
+.glyphicon-resize-horizontal { &:before { content: "\e120"; } }
+.glyphicon-hdd { &:before { content: "\e121"; } }
+.glyphicon-bullhorn { &:before { content: "\e122"; } }
+.glyphicon-bell { &:before { content: "\e123"; } }
+.glyphicon-certificate { &:before { content: "\e124"; } }
+.glyphicon-thumbs-up { &:before { content: "\e125"; } }
+.glyphicon-thumbs-down { &:before { content: "\e126"; } }
+.glyphicon-hand-right { &:before { content: "\e127"; } }
+.glyphicon-hand-left { &:before { content: "\e128"; } }
+.glyphicon-hand-up { &:before { content: "\e129"; } }
+.glyphicon-hand-down { &:before { content: "\e130"; } }
+.glyphicon-circle-arrow-right { &:before { content: "\e131"; } }
+.glyphicon-circle-arrow-left { &:before { content: "\e132"; } }
+.glyphicon-circle-arrow-up { &:before { content: "\e133"; } }
+.glyphicon-circle-arrow-down { &:before { content: "\e134"; } }
+.glyphicon-globe { &:before { content: "\e135"; } }
+.glyphicon-wrench { &:before { content: "\e136"; } }
+.glyphicon-tasks { &:before { content: "\e137"; } }
+.glyphicon-filter { &:before { content: "\e138"; } }
+.glyphicon-briefcase { &:before { content: "\e139"; } }
+.glyphicon-fullscreen { &:before { content: "\e140"; } }
+.glyphicon-dashboard { &:before { content: "\e141"; } }
+.glyphicon-paperclip { &:before { content: "\e142"; } }
+.glyphicon-heart-empty { &:before { content: "\e143"; } }
+.glyphicon-link { &:before { content: "\e144"; } }
+.glyphicon-phone { &:before { content: "\e145"; } }
+.glyphicon-pushpin { &:before { content: "\e146"; } }
+.glyphicon-usd { &:before { content: "\e148"; } }
+.glyphicon-gbp { &:before { content: "\e149"; } }
+.glyphicon-sort { &:before { content: "\e150"; } }
+.glyphicon-sort-by-alphabet { &:before { content: "\e151"; } }
+.glyphicon-sort-by-alphabet-alt { &:before { content: "\e152"; } }
+.glyphicon-sort-by-order { &:before { content: "\e153"; } }
+.glyphicon-sort-by-order-alt { &:before { content: "\e154"; } }
+.glyphicon-sort-by-attributes { &:before { content: "\e155"; } }
+.glyphicon-sort-by-attributes-alt { &:before { content: "\e156"; } }
+.glyphicon-unchecked { &:before { content: "\e157"; } }
+.glyphicon-expand { &:before { content: "\e158"; } }
+.glyphicon-collapse-down { &:before { content: "\e159"; } }
+.glyphicon-collapse-up { &:before { content: "\e160"; } }
+.glyphicon-log-in { &:before { content: "\e161"; } }
+.glyphicon-flash { &:before { content: "\e162"; } }
+.glyphicon-log-out { &:before { content: "\e163"; } }
+.glyphicon-new-window { &:before { content: "\e164"; } }
+.glyphicon-record { &:before { content: "\e165"; } }
+.glyphicon-save { &:before { content: "\e166"; } }
+.glyphicon-open { &:before { content: "\e167"; } }
+.glyphicon-saved { &:before { content: "\e168"; } }
+.glyphicon-import { &:before { content: "\e169"; } }
+.glyphicon-export { &:before { content: "\e170"; } }
+.glyphicon-send { &:before { content: "\e171"; } }
+.glyphicon-floppy-disk { &:before { content: "\e172"; } }
+.glyphicon-floppy-saved { &:before { content: "\e173"; } }
+.glyphicon-floppy-remove { &:before { content: "\e174"; } }
+.glyphicon-floppy-save { &:before { content: "\e175"; } }
+.glyphicon-floppy-open { &:before { content: "\e176"; } }
+.glyphicon-credit-card { &:before { content: "\e177"; } }
+.glyphicon-transfer { &:before { content: "\e178"; } }
+.glyphicon-cutlery { &:before { content: "\e179"; } }
+.glyphicon-header { &:before { content: "\e180"; } }
+.glyphicon-compressed { &:before { content: "\e181"; } }
+.glyphicon-earphone { &:before { content: "\e182"; } }
+.glyphicon-phone-alt { &:before { content: "\e183"; } }
+.glyphicon-tower { &:before { content: "\e184"; } }
+.glyphicon-stats { &:before { content: "\e185"; } }
+.glyphicon-sd-video { &:before { content: "\e186"; } }
+.glyphicon-hd-video { &:before { content: "\e187"; } }
+.glyphicon-subtitles { &:before { content: "\e188"; } }
+.glyphicon-sound-stereo { &:before { content: "\e189"; } }
+.glyphicon-sound-dolby { &:before { content: "\e190"; } }
+.glyphicon-sound-5-1 { &:before { content: "\e191"; } }
+.glyphicon-sound-6-1 { &:before { content: "\e192"; } }
+.glyphicon-sound-7-1 { &:before { content: "\e193"; } }
+.glyphicon-copyright-mark { &:before { content: "\e194"; } }
+.glyphicon-registration-mark { &:before { content: "\e195"; } }
+.glyphicon-cloud-download { &:before { content: "\e197"; } }
+.glyphicon-cloud-upload { &:before { content: "\e198"; } }
+.glyphicon-tree-conifer { &:before { content: "\e199"; } }
+.glyphicon-tree-deciduous { &:before { content: "\e200"; } }
diff --git a/bower_components/bootstrap/less/grid.less b/bower_components/bootstrap/less/grid.less
new file mode 100644
index 0000000..e100655
--- /dev/null
+++ b/bower_components/bootstrap/less/grid.less
@@ -0,0 +1,84 @@
+//
+// Grid system
+// --------------------------------------------------
+
+
+// Container widths
+//
+// Set the container width, and override it for fixed navbars in media queries.
+
+.container {
+ .container-fixed();
+
+ @media (min-width: @screen-sm-min) {
+ width: @container-sm;
+ }
+ @media (min-width: @screen-md-min) {
+ width: @container-md;
+ }
+ @media (min-width: @screen-lg-min) {
+ width: @container-lg;
+ }
+}
+
+
+// Fluid container
+//
+// Utilizes the mixin meant for fixed width containers, but without any defined
+// width for fluid, full width layouts.
+
+.container-fluid {
+ .container-fixed();
+}
+
+
+// Row
+//
+// Rows contain and clear the floats of your columns.
+
+.row {
+ .make-row();
+}
+
+
+// Columns
+//
+// Common styles for small and large grid columns
+
+.make-grid-columns();
+
+
+// Extra small grid
+//
+// Columns, offsets, pushes, and pulls for extra small devices like
+// smartphones.
+
+.make-grid(xs);
+
+
+// Small grid
+//
+// Columns, offsets, pushes, and pulls for the small device range, from phones
+// to tablets.
+
+@media (min-width: @screen-sm-min) {
+ .make-grid(sm);
+}
+
+
+// Medium grid
+//
+// Columns, offsets, pushes, and pulls for the desktop device range.
+
+@media (min-width: @screen-md-min) {
+ .make-grid(md);
+}
+
+
+// Large grid
+//
+// Columns, offsets, pushes, and pulls for the large desktop device range.
+
+@media (min-width: @screen-lg-min) {
+ .make-grid(lg);
+}
diff --git a/bower_components/bootstrap/less/input-groups.less b/bower_components/bootstrap/less/input-groups.less
new file mode 100644
index 0000000..a111474
--- /dev/null
+++ b/bower_components/bootstrap/less/input-groups.less
@@ -0,0 +1,162 @@
+//
+// Input groups
+// --------------------------------------------------
+
+// Base styles
+// -------------------------
+.input-group {
+ position: relative; // For dropdowns
+ display: table;
+ border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table
+
+ // Undo padding and float of grid classes
+ &[class*="col-"] {
+ float: none;
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .form-control {
+ // Ensure that the input is always above the *appended* addon button for
+ // proper border colors.
+ position: relative;
+ z-index: 2;
+
+ // IE9 fubars the placeholder attribute in text inputs and the arrows on
+ // select elements in input groups. To fix it, we float the input. Details:
+ // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855
+ float: left;
+
+ width: 100%;
+ margin-bottom: 0;
+ }
+}
+
+// Sizing options
+//
+// Remix the default form control sizing classes into new ones for easier
+// manipulation.
+
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn { .input-lg(); }
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn { .input-sm(); }
+
+
+// Display as table-cell
+// -------------------------
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+ display: table-cell;
+
+ &:not(:first-child):not(:last-child) {
+ border-radius: 0;
+ }
+}
+// Addon and addon wrapper for buttons
+.input-group-addon,
+.input-group-btn {
+ width: 1%;
+ white-space: nowrap;
+ vertical-align: middle; // Match the inputs
+}
+
+// Text input groups
+// -------------------------
+.input-group-addon {
+ padding: @padding-base-vertical @padding-base-horizontal;
+ font-size: @font-size-base;
+ font-weight: normal;
+ line-height: 1;
+ color: @input-color;
+ text-align: center;
+ background-color: @input-group-addon-bg;
+ border: 1px solid @input-group-addon-border-color;
+ border-radius: @border-radius-base;
+
+ // Sizing
+ &.input-sm {
+ padding: @padding-small-vertical @padding-small-horizontal;
+ font-size: @font-size-small;
+ border-radius: @border-radius-small;
+ }
+ &.input-lg {
+ padding: @padding-large-vertical @padding-large-horizontal;
+ font-size: @font-size-large;
+ border-radius: @border-radius-large;
+ }
+
+ // Nuke default margins from checkboxes and radios to vertically center within.
+ input[type="radio"],
+ input[type="checkbox"] {
+ margin-top: 0;
+ }
+}
+
+// Reset rounded corners
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+ .border-right-radius(0);
+}
+.input-group-addon:first-child {
+ border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+ .border-left-radius(0);
+}
+.input-group-addon:last-child {
+ border-left: 0;
+}
+
+// Button input groups
+// -------------------------
+.input-group-btn {
+ position: relative;
+ // Jankily prevent input button groups from wrapping with `white-space` and
+ // `font-size` in combination with `inline-block` on buttons.
+ font-size: 0;
+ white-space: nowrap;
+
+ // Negative margin for spacing, position for bringing hovered/focused/actived
+ // element above the siblings.
+ > .btn {
+ position: relative;
+ + .btn {
+ margin-left: -1px;
+ }
+ // Bring the "active" button to the front
+ &:hover,
+ &:focus,
+ &:active {
+ z-index: 2;
+ }
+ }
+
+ // Negative margin to only have a 1px border between the two
+ &:first-child {
+ > .btn,
+ > .btn-group {
+ margin-right: -1px;
+ }
+ }
+ &:last-child {
+ > .btn,
+ > .btn-group {
+ margin-left: -1px;
+ }
+ }
+}
diff --git a/bower_components/bootstrap/less/jumbotron.less b/bower_components/bootstrap/less/jumbotron.less
new file mode 100644
index 0000000..a15e169
--- /dev/null
+++ b/bower_components/bootstrap/less/jumbotron.less
@@ -0,0 +1,44 @@
+//
+// Jumbotron
+// --------------------------------------------------
+
+
+.jumbotron {
+ padding: @jumbotron-padding;
+ margin-bottom: @jumbotron-padding;
+ color: @jumbotron-color;
+ background-color: @jumbotron-bg;
+
+ h1,
+ .h1 {
+ color: @jumbotron-heading-color;
+ }
+ p {
+ margin-bottom: (@jumbotron-padding / 2);
+ font-size: @jumbotron-font-size;
+ font-weight: 200;
+ }
+
+ .container & {
+ border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container
+ }
+
+ .container {
+ max-width: 100%;
+ }
+
+ @media screen and (min-width: @screen-sm-min) {
+ padding-top: (@jumbotron-padding * 1.6);
+ padding-bottom: (@jumbotron-padding * 1.6);
+
+ .container & {
+ padding-left: (@jumbotron-padding * 2);
+ padding-right: (@jumbotron-padding * 2);
+ }
+
+ h1,
+ .h1 {
+ font-size: (@font-size-base * 4.5);
+ }
+ }
+}
diff --git a/bower_components/bootstrap/less/labels.less b/bower_components/bootstrap/less/labels.less
new file mode 100644
index 0000000..5db1ed1
--- /dev/null
+++ b/bower_components/bootstrap/less/labels.less
@@ -0,0 +1,64 @@
+//
+// Labels
+// --------------------------------------------------
+
+.label {
+ display: inline;
+ padding: .2em .6em .3em;
+ font-size: 75%;
+ font-weight: bold;
+ line-height: 1;
+ color: @label-color;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: .25em;
+
+ // Add hover effects, but only for links
+ &[href] {
+ &:hover,
+ &:focus {
+ color: @label-link-hover-color;
+ text-decoration: none;
+ cursor: pointer;
+ }
+ }
+
+ // Empty labels collapse automatically (not available in IE8)
+ &:empty {
+ display: none;
+ }
+
+ // Quick fix for labels in buttons
+ .btn & {
+ position: relative;
+ top: -1px;
+ }
+}
+
+// Colors
+// Contextual variations (linked labels get darker on :hover)
+
+.label-default {
+ .label-variant(@label-default-bg);
+}
+
+.label-primary {
+ .label-variant(@label-primary-bg);
+}
+
+.label-success {
+ .label-variant(@label-success-bg);
+}
+
+.label-info {
+ .label-variant(@label-info-bg);
+}
+
+.label-warning {
+ .label-variant(@label-warning-bg);
+}
+
+.label-danger {
+ .label-variant(@label-danger-bg);
+}
diff --git a/bower_components/bootstrap/less/list-group.less b/bower_components/bootstrap/less/list-group.less
new file mode 100644
index 0000000..3343f8e
--- /dev/null
+++ b/bower_components/bootstrap/less/list-group.less
@@ -0,0 +1,110 @@
+//
+// List groups
+// --------------------------------------------------
+
+
+// Base class
+//
+// Easily usable on <ul>, <ol>, or <div>.
+
+.list-group {
+ // No need to set list-style: none; since .list-group-item is block level
+ margin-bottom: 20px;
+ padding-left: 0; // reset padding because ul and ol
+}
+
+
+// Individual list items
+//
+// Use on `li`s or `div`s within the `.list-group` parent.
+
+.list-group-item {
+ position: relative;
+ display: block;
+ padding: 10px 15px;
+ // Place the border on the list items and negative margin up for better styling
+ margin-bottom: -1px;
+ background-color: @list-group-bg;
+ border: 1px solid @list-group-border;
+
+ // Round the first and last items
+ &:first-child {
+ .border-top-radius(@list-group-border-radius);
+ }
+ &:last-child {
+ margin-bottom: 0;
+ .border-bottom-radius(@list-group-border-radius);
+ }
+
+ // Align badges within list items
+ > .badge {
+ float: right;
+ }
+ > .badge + .badge {
+ margin-right: 5px;
+ }
+}
+
+
+// Linked list items
+//
+// Use anchor elements instead of `li`s or `div`s to create linked list items.
+// Includes an extra `.active` modifier class for showing selected items.
+
+a.list-group-item {
+ color: @list-group-link-color;
+
+ .list-group-item-heading {
+ color: @list-group-link-heading-color;
+ }
+
+ // Hover state
+ &:hover,
+ &:focus {
+ text-decoration: none;
+ background-color: @list-group-hover-bg;
+ }
+
+ // Active class on item itself, not parent
+ &.active,
+ &.active:hover,
+ &.active:focus {
+ z-index: 2; // Place active items above their siblings for proper border styling
+ color: @list-group-active-color;
+ background-color: @list-group-active-bg;
+ border-color: @list-group-active-border;
+
+ // Force color to inherit for custom content
+ .list-group-item-heading {
+ color: inherit;
+ }
+ .list-group-item-text {
+ color: @list-group-active-text-color;
+ }
+ }
+}
+
+
+// Contextual variants
+//
+// Add modifier classes to change text and background color on individual items.
+// Organizationally, this must come after the `:hover` states.
+
+.list-group-item-variant(success; @state-success-bg; @state-success-text);
+.list-group-item-variant(info; @state-info-bg; @state-info-text);
+.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);
+.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);
+
+
+// Custom content options
+//
+// Extra classes for creating well-formatted content within `.list-group-item`s.
+
+.list-group-item-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+.list-group-item-text {
+ margin-bottom: 0;
+ line-height: 1.3;
+}
diff --git a/bower_components/bootstrap/less/media.less b/bower_components/bootstrap/less/media.less
new file mode 100644
index 0000000..5ad22cd
--- /dev/null
+++ b/bower_components/bootstrap/less/media.less
@@ -0,0 +1,56 @@
+// Media objects
+// Source: http://stubbornella.org/content/?p=497
+// --------------------------------------------------
+
+
+// Common styles
+// -------------------------
+
+// Clear the floats
+.media,
+.media-body {
+ overflow: hidden;
+ zoom: 1;
+}
+
+// Proper spacing between instances of .media
+.media,
+.media .media {
+ margin-top: 15px;
+}
+.media:first-child {
+ margin-top: 0;
+}
+
+// For images and videos, set to block
+.media-object {
+ display: block;
+}
+
+// Reset margins on headings for tighter default spacing
+.media-heading {
+ margin: 0 0 5px;
+}
+
+
+// Media image alignment
+// -------------------------
+
+.media {
+ > .pull-left {
+ margin-right: 10px;
+ }
+ > .pull-right {
+ margin-left: 10px;
+ }
+}
+
+
+// Media list variation
+// -------------------------
+
+// Undo default ul/ol styles
+.media-list {
+ padding-left: 0;
+ list-style: none;
+}
diff --git a/bower_components/bootstrap/less/mixins.less b/bower_components/bootstrap/less/mixins.less
new file mode 100644
index 0000000..71723db
--- /dev/null
+++ b/bower_components/bootstrap/less/mixins.less
@@ -0,0 +1,929 @@
+//
+// Mixins
+// --------------------------------------------------
+
+
+// Utilities
+// -------------------------
+
+// Clearfix
+// Source: http://nicolasgallagher.com/micro-clearfix-hack/
+//
+// For modern browsers
+// 1. The space content is one way to avoid an Opera bug when the
+// contenteditable attribute is included anywhere else in the document.
+// Otherwise it causes space to appear at the top and bottom of elements
+// that are clearfixed.
+// 2. The use of `table` rather than `block` is only necessary if using
+// `:before` to contain the top-margins of child elements.
+.clearfix() {
+ &:before,
+ &:after {
+ content: " "; // 1
+ display: table; // 2
+ }
+ &:after {
+ clear: both;
+ }
+}
+
+// WebKit-style focus
+.tab-focus() {
+ // Default
+ outline: thin dotted;
+ // WebKit
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+
+// Center-align a block level element
+.center-block() {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+// Sizing shortcuts
+.size(@width; @height) {
+ width: @width;
+ height: @height;
+}
+.square(@size) {
+ .size(@size; @size);
+}
+
+// Placeholder text
+.placeholder(@color: @input-color-placeholder) {
+ &::-moz-placeholder { color: @color; // Firefox
+ opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526
+ &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+
+ &::-webkit-input-placeholder { color: @color; } // Safari and Chrome
+}
+
+// Text overflow
+// Requires inline-block or block for proper styling
+.text-overflow() {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+// CSS image replacement
+//
+// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for
+// mixins being reused as classes with the same name, this doesn't hold up. As
+// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note
+// that we cannot chain the mixins together in Less, so they are repeated.
+//
+// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757
+
+// Deprecated as of v3.0.1 (will be removed in v4)
+.hide-text() {
+ font: ~"0/0" a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+// New mixin to use as of v3.0.1
+.text-hide() {
+ .hide-text();
+}
+
+
+
+// CSS3 PROPERTIES
+// --------------------------------------------------
+
+// Single side border-radius
+.border-top-radius(@radius) {
+ border-top-right-radius: @radius;
+ border-top-left-radius: @radius;
+}
+.border-right-radius(@radius) {
+ border-bottom-right-radius: @radius;
+ border-top-right-radius: @radius;
+}
+.border-bottom-radius(@radius) {
+ border-bottom-right-radius: @radius;
+ border-bottom-left-radius: @radius;
+}
+.border-left-radius(@radius) {
+ border-bottom-left-radius: @radius;
+ border-top-left-radius: @radius;
+}
+
+// Drop shadows
+//
+// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's
+// supported browsers that have box shadow capabilities now support the
+// standard `box-shadow` property.
+.box-shadow(@shadow) {
+ -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1
+ box-shadow: @shadow;
+}
+
+// Transitions
+.transition(@transition) {
+ -webkit-transition: @transition;
+ transition: @transition;
+}
+.transition-property(@transition-property) {
+ -webkit-transition-property: @transition-property;
+ transition-property: @transition-property;
+}
+.transition-delay(@transition-delay) {
+ -webkit-transition-delay: @transition-delay;
+ transition-delay: @transition-delay;
+}
+.transition-duration(@transition-duration) {
+ -webkit-transition-duration: @transition-duration;
+ transition-duration: @transition-duration;
+}
+.transition-transform(@transition) {
+ -webkit-transition: -webkit-transform @transition;
+ -moz-transition: -moz-transform @transition;
+ -o-transition: -o-transform @transition;
+ transition: transform @transition;
+}
+
+// Transformations
+.rotate(@degrees) {
+ -webkit-transform: rotate(@degrees);
+ -ms-transform: rotate(@degrees); // IE9 only
+ transform: rotate(@degrees);
+}
+.scale(@ratio; @ratio-y...) {
+ -webkit-transform: scale(@ratio, @ratio-y);
+ -ms-transform: scale(@ratio, @ratio-y); // IE9 only
+ transform: scale(@ratio, @ratio-y);
+}
+.translate(@x; @y) {
+ -webkit-transform: translate(@x, @y);
+ -ms-transform: translate(@x, @y); // IE9 only
+ transform: translate(@x, @y);
+}
+.skew(@x; @y) {
+ -webkit-transform: skew(@x, @y);
+ -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+
+ transform: skew(@x, @y);
+}
+.translate3d(@x; @y; @z) {
+ -webkit-transform: translate3d(@x, @y, @z);
+ transform: translate3d(@x, @y, @z);
+}
+
+.rotateX(@degrees) {
+ -webkit-transform: rotateX(@degrees);
+ -ms-transform: rotateX(@degrees); // IE9 only
+ transform: rotateX(@degrees);
+}
+.rotateY(@degrees) {
+ -webkit-transform: rotateY(@degrees);
+ -ms-transform: rotateY(@degrees); // IE9 only
+ transform: rotateY(@degrees);
+}
+.perspective(@perspective) {
+ -webkit-perspective: @perspective;
+ -moz-perspective: @perspective;
+ perspective: @perspective;
+}
+.perspective-origin(@perspective) {
+ -webkit-perspective-origin: @perspective;
+ -moz-perspective-origin: @perspective;
+ perspective-origin: @perspective;
+}
+.transform-origin(@origin) {
+ -webkit-transform-origin: @origin;
+ -moz-transform-origin: @origin;
+ -ms-transform-origin: @origin; // IE9 only
+ transform-origin: @origin;
+}
+
+// Animations
+.animation(@animation) {
+ -webkit-animation: @animation;
+ animation: @animation;
+}
+.animation-name(@name) {
+ -webkit-animation-name: @name;
+ animation-name: @name;
+}
+.animation-duration(@duration) {
+ -webkit-animation-duration: @duration;
+ animation-duration: @duration;
+}
+.animation-timing-function(@timing-function) {
+ -webkit-animation-timing-function: @timing-function;
+ animation-timing-function: @timing-function;
+}
+.animation-delay(@delay) {
+ -webkit-animation-delay: @delay;
+ animation-delay: @delay;
+}
+.animation-iteration-count(@iteration-count) {
+ -webkit-animation-iteration-count: @iteration-count;
+ animation-iteration-count: @iteration-count;
+}
+.animation-direction(@direction) {
+ -webkit-animation-direction: @direction;
+ animation-direction: @direction;
+}
+
+// Backface visibility
+// Prevent browsers from flickering when using CSS 3D transforms.
+// Default value is `visible`, but can be changed to `hidden`
+.backface-visibility(@visibility){
+ -webkit-backface-visibility: @visibility;
+ -moz-backface-visibility: @visibility;
+ backface-visibility: @visibility;
+}
+
+// Box sizing
+.box-sizing(@boxmodel) {
+ -webkit-box-sizing: @boxmodel;
+ -moz-box-sizing: @boxmodel;
+ box-sizing: @boxmodel;
+}
+
+// User select
+// For selecting text on the page
+.user-select(@select) {
+ -webkit-user-select: @select;
+ -moz-user-select: @select;
+ -ms-user-select: @select; // IE10+
+ user-select: @select;
+}
+
+// Resize anything
+.resizable(@direction) {
+ resize: @direction; // Options: horizontal, vertical, both
+ overflow: auto; // Safari fix
+}
+
+// CSS3 Content Columns
+.content-columns(@column-count; @column-gap: @grid-gutter-width) {
+ -webkit-column-count: @column-count;
+ -moz-column-count: @column-count;
+ column-count: @column-count;
+ -webkit-column-gap: @column-gap;
+ -moz-column-gap: @column-gap;
+ column-gap: @column-gap;
+}
+
+// Optional hyphenation
+.hyphens(@mode: auto) {
+ word-wrap: break-word;
+ -webkit-hyphens: @mode;
+ -moz-hyphens: @mode;
+ -ms-hyphens: @mode; // IE10+
+ -o-hyphens: @mode;
+ hyphens: @mode;
+}
+
+// Opacity
+.opacity(@opacity) {
+ opacity: @opacity;
+ // IE8 filter
+ @opacity-ie: (@opacity * 100);
+ filter: ~"alpha(opacity=@{opacity-ie})";
+}
+
+
+
+// GRADIENTS
+// --------------------------------------------------
+
+#gradient {
+
+ // Horizontal gradient, from left to right
+ //
+ // Creates two color stops, start and end, by specifying a color and position for each color stop.
+ // Color stops are not available in IE9 and below.
+ .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {
+ background-image: -webkit-linear-gradient(left, color-stop(@start-color @start-percent), color-stop(@end-color @end-percent)); // Safari 5.1-6, Chrome 10+
+ background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
+ background-repeat: repeat-x;
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@start-color),argb(@end-color))); // IE9 and down
+ }
+
+ // Vertical gradient, from top to bottom
+ //
+ // Creates two color stops, start and end, by specifying a color and position for each color stop.
+ // Color stops are not available in IE9 and below.
+ .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {
+ background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+
+ background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
+ background-repeat: repeat-x;
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start-color),argb(@end-color))); // IE9 and down
+ }
+
+ .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {
+ background-repeat: repeat-x;
+ background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+
+ background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
+ }
+ .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {
+ background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);
+ background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);
+ background-repeat: no-repeat;
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback
+ }
+ .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {
+ background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);
+ background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);
+ background-repeat: no-repeat;
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback
+ }
+ .radial(@inner-color: #555; @outer-color: #333) {
+ background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);
+ background-image: radial-gradient(circle, @inner-color, @outer-color);
+ background-repeat: no-repeat;
+ }
+ .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {
+ background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);
+ background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);
+ }
+}
+
+// Reset filters for IE
+//
+// When you need to remove a gradient background, do not forget to use this to reset
+// the IE filter for IE9 and below.
+.reset-filter() {
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)"));
+}
+
+
+
+// Retina images
+//
+// Short retina mixin for setting background-image and -size
+
+.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {
+ background-image: url("@{file-1x}");
+
+ @media
+ only screen and (-webkit-min-device-pixel-ratio: 2),
+ only screen and ( min--moz-device-pixel-ratio: 2),
+ only screen and ( -o-min-device-pixel-ratio: 2/1),
+ only screen and ( min-device-pixel-ratio: 2),
+ only screen and ( min-resolution: 192dpi),
+ only screen and ( min-resolution: 2dppx) {
+ background-image: url("@{file-2x}");
+ background-size: @width-1x @height-1x;
+ }
+}
+
+
+// Responsive image
+//
+// Keep images from scaling beyond the width of their parents.
+
+.img-responsive(@display: block) {
+ display: @display;
+ max-width: 100%; // Part 1: Set a maximum relative to the parent
+ height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching
+}
+
+
+// COMPONENT MIXINS
+// --------------------------------------------------
+
+// Horizontal dividers
+// -------------------------
+// Dividers (basically an hr) within dropdowns and nav lists
+.nav-divider(@color: #e5e5e5) {
+ height: 1px;
+ margin: ((@line-height-computed / 2) - 1) 0;
+ overflow: hidden;
+ background-color: @color;
+}
+
+// Panels
+// -------------------------
+.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {
+ border-color: @border;
+
+ & > .panel-heading {
+ color: @heading-text-color;
+ background-color: @heading-bg-color;
+ border-color: @heading-border;
+
+ + .panel-collapse .panel-body {
+ border-top-color: @border;
+ }
+ }
+ & > .panel-footer {
+ + .panel-collapse .panel-body {
+ border-bottom-color: @border;
+ }
+ }
+}
+
+// Alerts
+// -------------------------
+.alert-variant(@background; @border; @text-color) {
+ background-color: @background;
+ border-color: @border;
+ color: @text-color;
+
+ hr {
+ border-top-color: darken(@border, 5%);
+ }
+ .alert-link {
+ color: darken(@text-color, 10%);
+ }
+}
+
+// Tables
+// -------------------------
+.table-row-variant(@state; @background) {
+ // Exact selectors below required to override `.table-striped` and prevent
+ // inheritance to nested tables.
+ .table > thead > tr,
+ .table > tbody > tr,
+ .table > tfoot > tr {
+ > td.@{state},
+ > th.@{state},
+ &.@{state} > td,
+ &.@{state} > th {
+ background-color: @background;
+ }
+ }
+
+ // Hover states for `.table-hover`
+ // Note: this is not available for cells or rows within `thead` or `tfoot`.
+ .table-hover > tbody > tr {
+ > td.@{state}:hover,
+ > th.@{state}:hover,
+ &.@{state}:hover > td,
+ &.@{state}:hover > th {
+ background-color: darken(@background, 5%);
+ }
+ }
+}
+
+// List Groups
+// -------------------------
+.list-group-item-variant(@state; @background; @color) {
+ .list-group-item-@{state} {
+ color: @color;
+ background-color: @background;
+
+ a& {
+ color: @color;
+
+ .list-group-item-heading { color: inherit; }
+
+ &:hover,
+ &:focus {
+ color: @color;
+ background-color: darken(@background, 5%);
+ }
+ &.active,
+ &.active:hover,
+ &.active:focus {
+ color: #fff;
+ background-color: @color;
+ border-color: @color;
+ }
+ }
+ }
+}
+
+// Button variants
+// -------------------------
+// Easily pump out default styles, as well as :hover, :focus, :active,
+// and disabled options for all buttons
+.button-variant(@color; @background; @border) {
+ color: @color;
+ background-color: @background;
+ border-color: @border;
+
+ &:hover,
+ &:focus,
+ &:active,
+ &.active,
+ .open .dropdown-toggle& {
+ color: @color;
+ background-color: darken(@background, 8%);
+ border-color: darken(@border, 12%);
+ }
+ &:active,
+ &.active,
+ .open .dropdown-toggle& {
+ background-image: none;
+ }
+ &.disabled,
+ &[disabled],
+ fieldset[disabled] & {
+ &,
+ &:hover,
+ &:focus,
+ &:active,
+ &.active {
+ background-color: @background;
+ border-color: @border;
+ }
+ }
+
+ .badge {
+ color: @background;
+ background-color: @color;
+ }
+}
+
+// Button sizes
+// -------------------------
+.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {
+ padding: @padding-vertical @padding-horizontal;
+ font-size: @font-size;
+ line-height: @line-height;
+ border-radius: @border-radius;
+}
+
+// Pagination
+// -------------------------
+.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {
+ > li {
+ > a,
+ > span {
+ padding: @padding-vertical @padding-horizontal;
+ font-size: @font-size;
+ }
+ &:first-child {
+ > a,
+ > span {
+ .border-left-radius(@border-radius);
+ }
+ }
+ &:last-child {
+ > a,
+ > span {
+ .border-right-radius(@border-radius);
+ }
+ }
+ }
+}
+
+// Labels
+// -------------------------
+.label-variant(@color) {
+ background-color: @color;
+ &[href] {
+ &:hover,
+ &:focus {
+ background-color: darken(@color, 10%);
+ }
+ }
+}
+
+// Contextual backgrounds
+// -------------------------
+.bg-variant(@color) {
+ background-color: @color;
+ a&:hover {
+ background-color: darken(@color, 10%);
+ }
+}
+
+// Typography
+// -------------------------
+.text-emphasis-variant(@color) {
+ color: @color;
+ a&:hover {
+ color: darken(@color, 10%);
+ }
+}
+
+// Navbar vertical align
+// -------------------------
+// Vertically center elements in the navbar.
+// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.
+.navbar-vertical-align(@element-height) {
+ margin-top: ((@navbar-height - @element-height) / 2);
+ margin-bottom: ((@navbar-height - @element-height) / 2);
+}
+
+// Progress bars
+// -------------------------
+.progress-bar-variant(@color) {
+ background-color: @color;
+ .progress-striped & {
+ #gradient > .striped();
+ }
+}
+
+// Responsive utilities
+// -------------------------
+// More easily include all the states for responsive-utilities.less.
+.responsive-visibility() {
+ display: block !important;
+ table& { display: table; }
+ tr& { display: table-row !important; }
+ th&,
+ td& { display: table-cell !important; }
+}
+
+.responsive-invisibility() {
+ display: none !important;
+}
+
+
+// Grid System
+// -----------
+
+// Centered container element
+.container-fixed() {
+ margin-right: auto;
+ margin-left: auto;
+ padding-left: (@grid-gutter-width / 2);
+ padding-right: (@grid-gutter-width / 2);
+ &:extend(.clearfix all);
+}
+
+// Creates a wrapper for a series of columns
+.make-row(@gutter: @grid-gutter-width) {
+ margin-left: (@gutter / -2);
+ margin-right: (@gutter / -2);
+ &:extend(.clearfix all);
+}
+
+// Generate the extra small columns
+.make-xs-column(@columns; @gutter: @grid-gutter-width) {
+ position: relative;
+ float: left;
+ width: percentage((@columns / @grid-columns));
+ min-height: 1px;
+ padding-left: (@gutter / 2);
+ padding-right: (@gutter / 2);
+}
+.make-xs-column-offset(@columns) {
+ @media (min-width: @screen-xs-min) {
+ margin-left: percentage((@columns / @grid-columns));
+ }
+}
+.make-xs-column-push(@columns) {
+ @media (min-width: @screen-xs-min) {
+ left: percentage((@columns / @grid-columns));
+ }
+}
+.make-xs-column-pull(@columns) {
+ @media (min-width: @screen-xs-min) {
+ right: percentage((@columns / @grid-columns));
+ }
+}
+
+
+// Generate the small columns
+.make-sm-column(@columns; @gutter: @grid-gutter-width) {
+ position: relative;
+ min-height: 1px;
+ padding-left: (@gutter / 2);
+ padding-right: (@gutter / 2);
+
+ @media (min-width: @screen-sm-min) {
+ float: left;
+ width: percentage((@columns / @grid-columns));
+ }
+}
+.make-sm-column-offset(@columns) {
+ @media (min-width: @screen-sm-min) {
+ margin-left: percentage((@columns / @grid-columns));
+ }
+}
+.make-sm-column-push(@columns) {
+ @media (min-width: @screen-sm-min) {
+ left: percentage((@columns / @grid-columns));
+ }
+}
+.make-sm-column-pull(@columns) {
+ @media (min-width: @screen-sm-min) {
+ right: percentage((@columns / @grid-columns));
+ }
+}
+
+
+// Generate the medium columns
+.make-md-column(@columns; @gutter: @grid-gutter-width) {
+ position: relative;
+ min-height: 1px;
+ padding-left: (@gutter / 2);
+ padding-right: (@gutter / 2);
+
+ @media (min-width: @screen-md-min) {
+ float: left;
+ width: percentage((@columns / @grid-columns));
+ }
+}
+.make-md-column-offset(@columns) {
+ @media (min-width: @screen-md-min) {
+ margin-left: percentage((@columns / @grid-columns));
+ }
+}
+.make-md-column-push(@columns) {
+ @media (min-width: @screen-md-min) {
+ left: percentage((@columns / @grid-columns));
+ }
+}
+.make-md-column-pull(@columns) {
+ @media (min-width: @screen-md-min) {
+ right: percentage((@columns / @grid-columns));
+ }
+}
+
+
+// Generate the large columns
+.make-lg-column(@columns; @gutter: @grid-gutter-width) {
+ position: relative;
+ min-height: 1px;
+ padding-left: (@gutter / 2);
+ padding-right: (@gutter / 2);
+
+ @media (min-width: @screen-lg-min) {
+ float: left;
+ width: percentage((@columns / @grid-columns));
+ }
+}
+.make-lg-column-offset(@columns) {
+ @media (min-width: @screen-lg-min) {
+ margin-left: percentage((@columns / @grid-columns));
+ }
+}
+.make-lg-column-push(@columns) {
+ @media (min-width: @screen-lg-min) {
+ left: percentage((@columns / @grid-columns));
+ }
+}
+.make-lg-column-pull(@columns) {
+ @media (min-width: @screen-lg-min) {
+ right: percentage((@columns / @grid-columns));
+ }
+}
+
+
+// Framework grid generation
+//
+// Used only by Bootstrap to generate the correct number of grid classes given
+// any value of `@grid-columns`.
+
+.make-grid-columns() {
+ // Common styles for all sizes of grid columns, widths 1-12
+ .col(@index) when (@index = 1) { // initial
+ @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}";
+ .col((@index + 1), @item);
+ }
+ .col(@index, @list) when (@index =< @grid-columns) { // general; "=<" isn't a typo
+ @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}";
+ .col((@index + 1), ~"@{list}, @{item}");
+ }
+ .col(@index, @list) when (@index > @grid-columns) { // terminal
+ @{list} {
+ position: relative;
+ // Prevent columns from collapsing when empty
+ min-height: 1px;
+ // Inner gutter via padding
+ padding-left: (@grid-gutter-width / 2);
+ padding-right: (@grid-gutter-width / 2);
+ }
+ }
+ .col(1); // kickstart it
+}
+
+.float-grid-columns(@class) {
+ .col(@index) when (@index = 1) { // initial
+ @item: ~".col-@{class}-@{index}";
+ .col((@index + 1), @item);
+ }
+ .col(@index, @list) when (@index =< @grid-columns) { // general
+ @item: ~".col-@{class}-@{index}";
+ .col((@index + 1), ~"@{list}, @{item}");
+ }
+ .col(@index, @list) when (@index > @grid-columns) { // terminal
+ @{list} {
+ float: left;
+ }
+ }
+ .col(1); // kickstart it
+}
+
+.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {
+ .col-@{class}-@{index} {
+ width: percentage((@index / @grid-columns));
+ }
+}
+.calc-grid-column(@index, @class, @type) when (@type = push) {
+ .col-@{class}-push-@{index} {
+ left: percentage((@index / @grid-columns));
+ }
+}
+.calc-grid-column(@index, @class, @type) when (@type = pull) {
+ .col-@{class}-pull-@{index} {
+ right: percentage((@index / @grid-columns));
+ }
+}
+.calc-grid-column(@index, @class, @type) when (@type = offset) {
+ .col-@{class}-offset-@{index} {
+ margin-left: percentage((@index / @grid-columns));
+ }
+}
+
+// Basic looping in LESS
+.loop-grid-columns(@index, @class, @type) when (@index >= 0) {
+ .calc-grid-column(@index, @class, @type);
+ // next iteration
+ .loop-grid-columns((@index - 1), @class, @type);
+}
+
+// Create grid for specific class
+.make-grid(@class) {
+ .float-grid-columns(@class);
+ .loop-grid-columns(@grid-columns, @class, width);
+ .loop-grid-columns(@grid-columns, @class, pull);
+ .loop-grid-columns(@grid-columns, @class, push);
+ .loop-grid-columns(@grid-columns, @class, offset);
+}
+
+// Form validation states
+//
+// Used in forms.less to generate the form validation CSS for warnings, errors,
+// and successes.
+
+.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {
+ // Color the label and help text
+ .help-block,
+ .control-label,
+ .radio,
+ .checkbox,
+ .radio-inline,
+ .checkbox-inline {
+ color: @text-color;
+ }
+ // Set the border and box shadow on specific inputs to match
+ .form-control {
+ border-color: @border-color;
+ .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work
+ &:focus {
+ border-color: darken(@border-color, 10%);
+ @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);
+ .box-shadow(@shadow);
+ }
+ }
+ // Set validation states also for addons
+ .input-group-addon {
+ color: @text-color;
+ border-color: @border-color;
+ background-color: @background-color;
+ }
+ // Optional feedback icon
+ .form-control-feedback {
+ color: @text-color;
+ }
+}
+
+// Form control focus state
+//
+// Generate a customized focus state and for any input with the specified color,
+// which defaults to the `@input-focus-border` variable.
+//
+// We highly encourage you to not customize the default value, but instead use
+// this to tweak colors on an as-needed basis. This aesthetic change is based on
+// WebKit's default styles, but applicable to a wider range of browsers. Its
+// usability and accessibility should be taken into account with any change.
+//
+// Example usage: change the default blue border and shadow to white for better
+// contrast against a dark gray background.
+
+.form-control-focus(@color: @input-border-focus) {
+ @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);
+ &:focus {
+ border-color: @color;
+ outline: 0;
+ .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}");
+ }
+}
+
+// Form control sizing
+//
+// Relative text size, padding, and border-radii changes for form controls. For
+// horizontal sizing, wrap controls in the predefined grid classes. `<select>`
+// element gets special love because it's special, and that's a fact!
+
+.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {
+ height: @input-height;
+ padding: @padding-vertical @padding-horizontal;
+ font-size: @font-size;
+ line-height: @line-height;
+ border-radius: @border-radius;
+
+ select& {
+ height: @input-height;
+ line-height: @input-height;
+ }
+
+ textarea&,
+ select[multiple]& {
+ height: auto;
+ }
+}
diff --git a/bower_components/bootstrap/less/modals.less b/bower_components/bootstrap/less/modals.less
new file mode 100644
index 0000000..21cdee0
--- /dev/null
+++ b/bower_components/bootstrap/less/modals.less
@@ -0,0 +1,139 @@
+//
+// Modals
+// --------------------------------------------------
+
+// .modal-open - body class for killing the scroll
+// .modal - container to scroll within
+// .modal-dialog - positioning shell for the actual modal
+// .modal-content - actual modal w/ bg and corners and shit
+
+// Kill the scroll on the body
+.modal-open {
+ overflow: hidden;
+}
+
+// Container that the modal scrolls within
+.modal {
+ display: none;
+ overflow: auto;
+ overflow-y: scroll;
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: @zindex-modal;
+ -webkit-overflow-scrolling: touch;
+
+ // Prevent Chrome on Windows from adding a focus outline. For details, see
+ // https://github.com/twbs/bootstrap/pull/10951.
+ outline: 0;
+
+ // When fading in the modal, animate it to slide down
+ &.fade .modal-dialog {
+ .translate(0, -25%);
+ .transition-transform(~"0.3s ease-out");
+ }
+ &.in .modal-dialog { .translate(0, 0)}
+}
+
+// Shell div to position the modal with bottom padding
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 10px;
+}
+
+// Actual modal
+.modal-content {
+ position: relative;
+ background-color: @modal-content-bg;
+ border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)
+ border: 1px solid @modal-content-border-color;
+ border-radius: @border-radius-large;
+ .box-shadow(0 3px 9px rgba(0,0,0,.5));
+ background-clip: padding-box;
+ // Remove focus outline from opened modal
+ outline: none;
+}
+
+// Modal background
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: @zindex-modal-background;
+ background-color: @modal-backdrop-bg;
+ // Fade for backdrop
+ &.fade { .opacity(0); }
+ &.in { .opacity(@modal-backdrop-opacity); }
+}
+
+// Modal header
+// Top section of the modal w/ title and dismiss
+.modal-header {
+ padding: @modal-title-padding;
+ border-bottom: 1px solid @modal-header-border-color;
+ min-height: (@modal-title-padding + @modal-title-line-height);
+}
+// Close icon
+.modal-header .close {
+ margin-top: -2px;
+}
+
+// Title text within header
+.modal-title {
+ margin: 0;
+ line-height: @modal-title-line-height;
+}
+
+// Modal body
+// Where all modal content resides (sibling of .modal-header and .modal-footer)
+.modal-body {
+ position: relative;
+ padding: @modal-inner-padding;
+}
+
+// Footer (for actions)
+.modal-footer {
+ margin-top: 15px;
+ padding: (@modal-inner-padding - 1) @modal-inner-padding @modal-inner-padding;
+ text-align: right; // right align buttons
+ border-top: 1px solid @modal-footer-border-color;
+ &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons
+
+ // Properly space out buttons
+ .btn + .btn {
+ margin-left: 5px;
+ margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs
+ }
+ // but override that for button groups
+ .btn-group .btn + .btn {
+ margin-left: -1px;
+ }
+ // and override it for block buttons as well
+ .btn-block + .btn-block {
+ margin-left: 0;
+ }
+}
+
+// Scale up the modal
+@media (min-width: @screen-sm-min) {
+ // Automatically set modal's width for larger viewports
+ .modal-dialog {
+ width: @modal-md;
+ margin: 30px auto;
+ }
+ .modal-content {
+ .box-shadow(0 5px 15px rgba(0,0,0,.5));
+ }
+
+ // Modal sizes
+ .modal-sm { width: @modal-sm; }
+}
+
+@media (min-width: @screen-md-min) {
+ .modal-lg { width: @modal-lg; }
+}
diff --git a/bower_components/bootstrap/less/navbar.less b/bower_components/bootstrap/less/navbar.less
new file mode 100644
index 0000000..8c4c210
--- /dev/null
+++ b/bower_components/bootstrap/less/navbar.less
@@ -0,0 +1,616 @@
+//
+// Navbars
+// --------------------------------------------------
+
+
+// Wrapper and base class
+//
+// Provide a static navbar from which we expand to create full-width, fixed, and
+// other navbar variations.
+
+.navbar {
+ position: relative;
+ min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)
+ margin-bottom: @navbar-margin-bottom;
+ border: 1px solid transparent;
+
+ // Prevent floats from breaking the navbar
+ &:extend(.clearfix all);
+
+ @media (min-width: @grid-float-breakpoint) {
+ border-radius: @navbar-border-radius;
+ }
+}
+
+
+// Navbar heading
+//
+// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy
+// styling of responsive aspects.
+
+.navbar-header {
+ &:extend(.clearfix all);
+
+ @media (min-width: @grid-float-breakpoint) {
+ float: left;
+ }
+}
+
+
+// Navbar collapse (body)
+//
+// Group your navbar content into this for easy collapsing and expanding across
+// various device sizes. By default, this content is collapsed when <768px, but
+// will expand past that for a horizontal display.
+//
+// To start (on mobile devices) the navbar links, forms, and buttons are stacked
+// vertically and include a `max-height` to overflow in case you have too much
+// content for the user's viewport.
+
+.navbar-collapse {
+ max-height: @navbar-collapse-max-height;
+ overflow-x: visible;
+ padding-right: @navbar-padding-horizontal;
+ padding-left: @navbar-padding-horizontal;
+ border-top: 1px solid transparent;
+ box-shadow: inset 0 1px 0 rgba(255,255,255,.1);
+ &:extend(.clearfix all);
+ -webkit-overflow-scrolling: touch;
+
+ &.in {
+ overflow-y: auto;
+ }
+
+ @media (min-width: @grid-float-breakpoint) {
+ width: auto;
+ border-top: 0;
+ box-shadow: none;
+
+ &.collapse {
+ display: block !important;
+ height: auto !important;
+ padding-bottom: 0; // Override default setting
+ overflow: visible !important;
+ }
+
+ &.in {
+ overflow-y: visible;
+ }
+
+ // Undo the collapse side padding for navbars with containers to ensure
+ // alignment of right-aligned contents.
+ .navbar-fixed-top &,
+ .navbar-static-top &,
+ .navbar-fixed-bottom & {
+ padding-left: 0;
+ padding-right: 0;
+ }
+ }
+}
+
+
+// Both navbar header and collapse
+//
+// When a container is present, change the behavior of the header and collapse.
+
+.container,
+.container-fluid {
+ > .navbar-header,
+ > .navbar-collapse {
+ margin-right: -@navbar-padding-horizontal;
+ margin-left: -@navbar-padding-horizontal;
+
+ @media (min-width: @grid-float-breakpoint) {
+ margin-right: 0;
+ margin-left: 0;
+ }
+ }
+}
+
+
+//
+// Navbar alignment options
+//
+// Display the navbar across the entirety of the page or fixed it to the top or
+// bottom of the page.
+
+// Static top (unfixed, but 100% wide) navbar
+.navbar-static-top {
+ z-index: @zindex-navbar;
+ border-width: 0 0 1px;
+
+ @media (min-width: @grid-float-breakpoint) {
+ border-radius: 0;
+ }
+}
+
+// Fix the top/bottom navbars when screen real estate supports it
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ position: fixed;
+ right: 0;
+ left: 0;
+ z-index: @zindex-navbar-fixed;
+
+ // Undo the rounded corners
+ @media (min-width: @grid-float-breakpoint) {
+ border-radius: 0;
+ }
+}
+.navbar-fixed-top {
+ top: 0;
+ border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+ bottom: 0;
+ margin-bottom: 0; // override .navbar defaults
+ border-width: 1px 0 0;
+}
+
+
+// Brand/project name
+
+.navbar-brand {
+ float: left;
+ padding: @navbar-padding-vertical @navbar-padding-horizontal;
+ font-size: @font-size-large;
+ line-height: @line-height-computed;
+ height: @navbar-height;
+
+ &:hover,
+ &:focus {
+ text-decoration: none;
+ }
+
+ @media (min-width: @grid-float-breakpoint) {
+ .navbar > .container &,
+ .navbar > .container-fluid & {
+ margin-left: -@navbar-padding-horizontal;
+ }
+ }
+}
+
+
+// Navbar toggle
+//
+// Custom button for toggling the `.navbar-collapse`, powered by the collapse
+// JavaScript plugin.
+
+.navbar-toggle {
+ position: relative;
+ float: right;
+ margin-right: @navbar-padding-horizontal;
+ padding: 9px 10px;
+ .navbar-vertical-align(34px);
+ background-color: transparent;
+ background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
+ border: 1px solid transparent;
+ border-radius: @border-radius-base;
+
+ // We remove the `outline` here, but later compensate by attaching `:hover`
+ // styles to `:focus`.
+ &:focus {
+ outline: none;
+ }
+
+ // Bars
+ .icon-bar {
+ display: block;
+ width: 22px;
+ height: 2px;
+ border-radius: 1px;
+ }
+ .icon-bar + .icon-bar {
+ margin-top: 4px;
+ }
+
+ @media (min-width: @grid-float-breakpoint) {
+ display: none;
+ }
+}
+
+
+// Navbar nav links
+//
+// Builds on top of the `.nav` components with its own modifier class to make
+// the nav the full height of the horizontal nav (above 768px).
+
+.navbar-nav {
+ margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;
+
+ > li > a {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ line-height: @line-height-computed;
+ }
+
+ @media (max-width: @grid-float-breakpoint-max) {
+ // Dropdowns get custom display when collapsed
+ .open .dropdown-menu {
+ position: static;
+ float: none;
+ width: auto;
+ margin-top: 0;
+ background-color: transparent;
+ border: 0;
+ box-shadow: none;
+ > li > a,
+ .dropdown-header {
+ padding: 5px 15px 5px 25px;
+ }
+ > li > a {
+ line-height: @line-height-computed;
+ &:hover,
+ &:focus {
+ background-image: none;
+ }
+ }
+ }
+ }
+
+ // Uncollapse the nav
+ @media (min-width: @grid-float-breakpoint) {
+ float: left;
+ margin: 0;
+
+ > li {
+ float: left;
+ > a {
+ padding-top: @navbar-padding-vertical;
+ padding-bottom: @navbar-padding-vertical;
+ }
+ }
+
+ &.navbar-right:last-child {
+ margin-right: -@navbar-padding-horizontal;
+ }
+ }
+}
+
+
+// Component alignment
+//
+// Repurpose the pull utilities as their own navbar utilities to avoid specificity
+// issues with parents and chaining. Only do this when the navbar is uncollapsed
+// though so that navbar contents properly stack and align in mobile.
+
+@media (min-width: @grid-float-breakpoint) {
+ .navbar-left { .pull-left(); }
+ .navbar-right { .pull-right(); }
+}
+
+
+// Navbar form
+//
+// Extension of the `.form-inline` with some extra flavor for optimum display in
+// our navbars.
+
+.navbar-form {
+ margin-left: -@navbar-padding-horizontal;
+ margin-right: -@navbar-padding-horizontal;
+ padding: 10px @navbar-padding-horizontal;
+ border-top: 1px solid transparent;
+ border-bottom: 1px solid transparent;
+ @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);
+ .box-shadow(@shadow);
+
+ // Mixin behavior for optimum display
+ .form-inline();
+
+ .form-group {
+ @media (max-width: @grid-float-breakpoint-max) {
+ margin-bottom: 5px;
+ }
+ }
+
+ // Vertically center in expanded, horizontal navbar
+ .navbar-vertical-align(@input-height-base);
+
+ // Undo 100% width for pull classes
+ @media (min-width: @grid-float-breakpoint) {
+ width: auto;
+ border: 0;
+ margin-left: 0;
+ margin-right: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ .box-shadow(none);
+
+ // Outdent the form if last child to line up with content down the page
+ &.navbar-right:last-child {
+ margin-right: -@navbar-padding-horizontal;
+ }
+ }
+}
+
+
+// Dropdown menus
+
+// Menu position and menu carets
+.navbar-nav > li > .dropdown-menu {
+ margin-top: 0;
+ .border-top-radius(0);
+}
+// Menu position and menu caret support for dropups via extra dropup class
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+ .border-bottom-radius(0);
+}
+
+
+// Buttons in navbars
+//
+// Vertically center a button within a navbar (when *not* in a form).
+
+.navbar-btn {
+ .navbar-vertical-align(@input-height-base);
+
+ &.btn-sm {
+ .navbar-vertical-align(@input-height-small);
+ }
+ &.btn-xs {
+ .navbar-vertical-align(22);
+ }
+}
+
+
+// Text in navbars
+//
+// Add a class to make any element properly align itself vertically within the navbars.
+
+.navbar-text {
+ .navbar-vertical-align(@line-height-computed);
+
+ @media (min-width: @grid-float-breakpoint) {
+ float: left;
+ margin-left: @navbar-padding-horizontal;
+ margin-right: @navbar-padding-horizontal;
+
+ // Outdent the form if last child to line up with content down the page
+ &.navbar-right:last-child {
+ margin-right: 0;
+ }
+ }
+}
+
+// Alternate navbars
+// --------------------------------------------------
+
+// Default navbar
+.navbar-default {
+ background-color: @navbar-default-bg;
+ border-color: @navbar-default-border;
+
+ .navbar-brand {
+ color: @navbar-default-brand-color;
+ &:hover,
+ &:focus {
+ color: @navbar-default-brand-hover-color;
+ background-color: @navbar-default-brand-hover-bg;
+ }
+ }
+
+ .navbar-text {
+ color: @navbar-default-color;
+ }
+
+ .navbar-nav {
+ > li > a {
+ color: @navbar-default-link-color;
+
+ &:hover,
+ &:focus {
+ color: @navbar-default-link-hover-color;
+ background-color: @navbar-default-link-hover-bg;
+ }
+ }
+ > .active > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @navbar-default-link-active-color;
+ background-color: @navbar-default-link-active-bg;
+ }
+ }
+ > .disabled > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @navbar-default-link-disabled-color;
+ background-color: @navbar-default-link-disabled-bg;
+ }
+ }
+ }
+
+ .navbar-toggle {
+ border-color: @navbar-default-toggle-border-color;
+ &:hover,
+ &:focus {
+ background-color: @navbar-default-toggle-hover-bg;
+ }
+ .icon-bar {
+ background-color: @navbar-default-toggle-icon-bar-bg;
+ }
+ }
+
+ .navbar-collapse,
+ .navbar-form {
+ border-color: @navbar-default-border;
+ }
+
+ // Dropdown menu items
+ .navbar-nav {
+ // Remove background color from open dropdown
+ > .open > a {
+ &,
+ &:hover,
+ &:focus {
+ background-color: @navbar-default-link-active-bg;
+ color: @navbar-default-link-active-color;
+ }
+ }
+
+ @media (max-width: @grid-float-breakpoint-max) {
+ // Dropdowns get custom display when collapsed
+ .open .dropdown-menu {
+ > li > a {
+ color: @navbar-default-link-color;
+ &:hover,
+ &:focus {
+ color: @navbar-default-link-hover-color;
+ background-color: @navbar-default-link-hover-bg;
+ }
+ }
+ > .active > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @navbar-default-link-active-color;
+ background-color: @navbar-default-link-active-bg;
+ }
+ }
+ > .disabled > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @navbar-default-link-disabled-color;
+ background-color: @navbar-default-link-disabled-bg;
+ }
+ }
+ }
+ }
+ }
+
+
+ // Links in navbars
+ //
+ // Add a class to ensure links outside the navbar nav are colored correctly.
+
+ .navbar-link {
+ color: @navbar-default-link-color;
+ &:hover {
+ color: @navbar-default-link-hover-color;
+ }
+ }
+
+}
+
+// Inverse navbar
+
+.navbar-inverse {
+ background-color: @navbar-inverse-bg;
+ border-color: @navbar-inverse-border;
+
+ .navbar-brand {
+ color: @navbar-inverse-brand-color;
+ &:hover,
+ &:focus {
+ color: @navbar-inverse-brand-hover-color;
+ background-color: @navbar-inverse-brand-hover-bg;
+ }
+ }
+
+ .navbar-text {
+ color: @navbar-inverse-color;
+ }
+
+ .navbar-nav {
+ > li > a {
+ color: @navbar-inverse-link-color;
+
+ &:hover,
+ &:focus {
+ color: @navbar-inverse-link-hover-color;
+ background-color: @navbar-inverse-link-hover-bg;
+ }
+ }
+ > .active > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @navbar-inverse-link-active-color;
+ background-color: @navbar-inverse-link-active-bg;
+ }
+ }
+ > .disabled > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @navbar-inverse-link-disabled-color;
+ background-color: @navbar-inverse-link-disabled-bg;
+ }
+ }
+ }
+
+ // Darken the responsive nav toggle
+ .navbar-toggle {
+ border-color: @navbar-inverse-toggle-border-color;
+ &:hover,
+ &:focus {
+ background-color: @navbar-inverse-toggle-hover-bg;
+ }
+ .icon-bar {
+ background-color: @navbar-inverse-toggle-icon-bar-bg;
+ }
+ }
+
+ .navbar-collapse,
+ .navbar-form {
+ border-color: darken(@navbar-inverse-bg, 7%);
+ }
+
+ // Dropdowns
+ .navbar-nav {
+ > .open > a {
+ &,
+ &:hover,
+ &:focus {
+ background-color: @navbar-inverse-link-active-bg;
+ color: @navbar-inverse-link-active-color;
+ }
+ }
+
+ @media (max-width: @grid-float-breakpoint-max) {
+ // Dropdowns get custom display
+ .open .dropdown-menu {
+ > .dropdown-header {
+ border-color: @navbar-inverse-border;
+ }
+ .divider {
+ background-color: @navbar-inverse-border;
+ }
+ > li > a {
+ color: @navbar-inverse-link-color;
+ &:hover,
+ &:focus {
+ color: @navbar-inverse-link-hover-color;
+ background-color: @navbar-inverse-link-hover-bg;
+ }
+ }
+ > .active > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @navbar-inverse-link-active-color;
+ background-color: @navbar-inverse-link-active-bg;
+ }
+ }
+ > .disabled > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @navbar-inverse-link-disabled-color;
+ background-color: @navbar-inverse-link-disabled-bg;
+ }
+ }
+ }
+ }
+ }
+
+ .navbar-link {
+ color: @navbar-inverse-link-color;
+ &:hover {
+ color: @navbar-inverse-link-hover-color;
+ }
+ }
+
+}
diff --git a/bower_components/bootstrap/less/navs.less b/bower_components/bootstrap/less/navs.less
new file mode 100644
index 0000000..9e729b3
--- /dev/null
+++ b/bower_components/bootstrap/less/navs.less
@@ -0,0 +1,242 @@
+//
+// Navs
+// --------------------------------------------------
+
+
+// Base class
+// --------------------------------------------------
+
+.nav {
+ margin-bottom: 0;
+ padding-left: 0; // Override default ul/ol
+ list-style: none;
+ &:extend(.clearfix all);
+
+ > li {
+ position: relative;
+ display: block;
+
+ > a {
+ position: relative;
+ display: block;
+ padding: @nav-link-padding;
+ &:hover,
+ &:focus {
+ text-decoration: none;
+ background-color: @nav-link-hover-bg;
+ }
+ }
+
+ // Disabled state sets text to gray and nukes hover/tab effects
+ &.disabled > a {
+ color: @nav-disabled-link-color;
+
+ &:hover,
+ &:focus {
+ color: @nav-disabled-link-hover-color;
+ text-decoration: none;
+ background-color: transparent;
+ cursor: not-allowed;
+ }
+ }
+ }
+
+ // Open dropdowns
+ .open > a {
+ &,
+ &:hover,
+ &:focus {
+ background-color: @nav-link-hover-bg;
+ border-color: @link-color;
+ }
+ }
+
+ // Nav dividers (deprecated with v3.0.1)
+ //
+ // This should have been removed in v3 with the dropping of `.nav-list`, but
+ // we missed it. We don't currently support this anywhere, but in the interest
+ // of maintaining backward compatibility in case you use it, it's deprecated.
+ .nav-divider {
+ .nav-divider();
+ }
+
+ // Prevent IE8 from misplacing imgs
+ //
+ // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989
+ > li > a > img {
+ max-width: none;
+ }
+}
+
+
+// Tabs
+// -------------------------
+
+// Give the tabs something to sit on
+.nav-tabs {
+ border-bottom: 1px solid @nav-tabs-border-color;
+ > li {
+ float: left;
+ // Make the list-items overlay the bottom border
+ margin-bottom: -1px;
+
+ // Actual tabs (as links)
+ > a {
+ margin-right: 2px;
+ line-height: @line-height-base;
+ border: 1px solid transparent;
+ border-radius: @border-radius-base @border-radius-base 0 0;
+ &:hover {
+ border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;
+ }
+ }
+
+ // Active state, and its :hover to override normal :hover
+ &.active > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @nav-tabs-active-link-hover-color;
+ background-color: @nav-tabs-active-link-hover-bg;
+ border: 1px solid @nav-tabs-active-link-hover-border-color;
+ border-bottom-color: transparent;
+ cursor: default;
+ }
+ }
+ }
+ // pulling this in mainly for less shorthand
+ &.nav-justified {
+ .nav-justified();
+ .nav-tabs-justified();
+ }
+}
+
+
+// Pills
+// -------------------------
+.nav-pills {
+ > li {
+ float: left;
+
+ // Links rendered as pills
+ > a {
+ border-radius: @nav-pills-border-radius;
+ }
+ + li {
+ margin-left: 2px;
+ }
+
+ // Active state
+ &.active > a {
+ &,
+ &:hover,
+ &:focus {
+ color: @nav-pills-active-link-hover-color;
+ background-color: @nav-pills-active-link-hover-bg;
+ }
+ }
+ }
+}
+
+
+// Stacked pills
+.nav-stacked {
+ > li {
+ float: none;
+ + li {
+ margin-top: 2px;
+ margin-left: 0; // no need for this gap between nav items
+ }
+ }
+}
+
+
+// Nav variations
+// --------------------------------------------------
+
+// Justified nav links
+// -------------------------
+
+.nav-justified {
+ width: 100%;
+
+ > li {
+ float: none;
+ > a {
+ text-align: center;
+ margin-bottom: 5px;
+ }
+ }
+
+ > .dropdown .dropdown-menu {
+ top: auto;
+ left: auto;
+ }
+
+ @media (min-width: @screen-sm-min) {
+ > li {
+ display: table-cell;
+ width: 1%;
+ > a {
+ margin-bottom: 0;
+ }
+ }
+ }
+}
+
+// Move borders to anchors instead of bottom of list
+//
+// Mixin for adding on top the shared `.nav-justified` styles for our tabs
+.nav-tabs-justified {
+ border-bottom: 0;
+
+ > li > a {
+ // Override margin from .nav-tabs
+ margin-right: 0;
+ border-radius: @border-radius-base;
+ }
+
+ > .active > a,
+ > .active > a:hover,
+ > .active > a:focus {
+ border: 1px solid @nav-tabs-justified-link-border-color;
+ }
+
+ @media (min-width: @screen-sm-min) {
+ > li > a {
+ border-bottom: 1px solid @nav-tabs-justified-link-border-color;
+ border-radius: @border-radius-base @border-radius-base 0 0;
+ }
+ > .active > a,
+ > .active > a:hover,
+ > .active > a:focus {
+ border-bottom-color: @nav-tabs-justified-active-link-border-color;
+ }
+ }
+}
+
+
+// Tabbable tabs
+// -------------------------
+
+// Hide tabbable panes to start, show them when `.active`
+.tab-content {
+ > .tab-pane {
+ display: none;
+ }
+ > .active {
+ display: block;
+ }
+}
+
+
+// Dropdowns
+// -------------------------
+
+// Specific dropdowns
+.nav-tabs .dropdown-menu {
+ // make dropdown border overlap tab border
+ margin-top: -1px;
+ // Remove the top rounded corners here since there is a hard edge above the menu
+ .border-top-radius(0);
+}
diff --git a/bower_components/bootstrap/less/normalize.less b/bower_components/bootstrap/less/normalize.less
new file mode 100644
index 0000000..024e257
--- /dev/null
+++ b/bower_components/bootstrap/less/normalize.less
@@ -0,0 +1,423 @@
+/*! normalize.css v3.0.0 | MIT License | git.io/normalize */
+
+//
+// 1. Set default font family to sans-serif.
+// 2. Prevent iOS text size adjust after orientation change, without disabling
+// user zoom.
+//
+
+html {
+ font-family: sans-serif; // 1
+ -ms-text-size-adjust: 100%; // 2
+ -webkit-text-size-adjust: 100%; // 2
+}
+
+//
+// Remove default margin.
+//
+
+body {
+ margin: 0;
+}
+
+// HTML5 display definitions
+// ==========================================================================
+
+//
+// Correct `block` display not defined in IE 8/9.
+//
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+ display: block;
+}
+
+//
+// 1. Correct `inline-block` display not defined in IE 8/9.
+// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+//
+
+audio,
+canvas,
+progress,
+video {
+ display: inline-block; // 1
+ vertical-align: baseline; // 2
+}
+
+//
+// Prevent modern browsers from displaying `audio` without controls.
+// Remove excess height in iOS 5 devices.
+//
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+//
+// Address `[hidden]` styling not present in IE 8/9.
+// Hide the `template` element in IE, Safari, and Firefox < 22.
+//
+
+[hidden],
+template {
+ display: none;
+}
+
+// Links
+// ==========================================================================
+
+//
+// Remove the gray background color from active links in IE 10.
+//
+
+a {
+ background: transparent;
+}
+
+//
+// Improve readability when focused and also mouse hovered in all browsers.
+//
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+// Text-level semantics
+// ==========================================================================
+
+//
+// Address styling not present in IE 8/9, Safari 5, and Chrome.
+//
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+//
+// Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
+//
+
+b,
+strong {
+ font-weight: bold;
+}
+
+//
+// Address styling not present in Safari 5 and Chrome.
+//
+
+dfn {
+ font-style: italic;
+}
+
+//
+// Address variable `h1` font-size and margin within `section` and `article`
+// contexts in Firefox 4+, Safari 5, and Chrome.
+//
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+//
+// Address styling not present in IE 8/9.
+//
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+//
+// Address inconsistent and variable font size in all browsers.
+//
+
+small {
+ font-size: 80%;
+}
+
+//
+// Prevent `sub` and `sup` affecting `line-height` in all browsers.
+//
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+// Embedded content
+// ==========================================================================
+
+//
+// Remove border when inside `a` element in IE 8/9.
+//
+
+img {
+ border: 0;
+}
+
+//
+// Correct overflow displayed oddly in IE 9.
+//
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+// Grouping content
+// ==========================================================================
+
+//
+// Address margin not present in IE 8/9 and Safari 5.
+//
+
+figure {
+ margin: 1em 40px;
+}
+
+//
+// Address differences between Firefox and other browsers.
+//
+
+hr {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ height: 0;
+}
+
+//
+// Contain overflow in all browsers.
+//
+
+pre {
+ overflow: auto;
+}
+
+//
+// Address odd `em`-unit font size rendering in all browsers.
+//
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+
+// Forms
+// ==========================================================================
+
+//
+// Known limitation: by default, Chrome and Safari on OS X allow very limited
+// styling of `select`, unless a `border` property is set.
+//
+
+//
+// 1. Correct color not being inherited.
+// Known issue: affects color of disabled elements.
+// 2. Correct font properties not being inherited.
+// 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
+//
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ color: inherit; // 1
+ font: inherit; // 2
+ margin: 0; // 3
+}
+
+//
+// Address `overflow` set to `hidden` in IE 8/9/10.
+//
+
+button {
+ overflow: visible;
+}
+
+//
+// Address inconsistent `text-transform` inheritance for `button` and `select`.
+// All other form control elements do not inherit `text-transform` values.
+// Correct `button` style inheritance in Firefox, IE 8+, and Opera
+// Correct `select` style inheritance in Firefox.
+//
+
+button,
+select {
+ text-transform: none;
+}
+
+//
+// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+// and `video` controls.
+// 2. Correct inability to style clickable `input` types in iOS.
+// 3. Improve usability and consistency of cursor style between image-type
+// `input` and others.
+//
+
+button,
+html input[type="button"], // 1
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; // 2
+ cursor: pointer; // 3
+}
+
+//
+// Re-set default cursor for disabled elements.
+//
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+//
+// Remove inner padding and border in Firefox 4+.
+//
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+//
+// Address Firefox 4+ setting `line-height` on `input` using `!important` in
+// the UA stylesheet.
+//
+
+input {
+ line-height: normal;
+}
+
+//
+// It's recommended that you don't attempt to style these elements.
+// Firefox's implementation doesn't respect box-sizing, padding, or width.
+//
+// 1. Address box sizing set to `content-box` in IE 8/9/10.
+// 2. Remove excess padding in IE 8/9/10.
+//
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; // 1
+ padding: 0; // 2
+}
+
+//
+// Fix the cursor style for Chrome's increment/decrement buttons. For certain
+// `font-size` values of the `input`, it causes the cursor style of the
+// decrement button to change from `default` to `text`.
+//
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+//
+// 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
+// 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
+// (include `-moz` to future-proof).
+//
+
+input[type="search"] {
+ -webkit-appearance: textfield; // 1
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; // 2
+ box-sizing: content-box;
+}
+
+//
+// Remove inner padding and search cancel button in Safari and Chrome on OS X.
+// Safari (but not Chrome) clips the cancel button when the search input has
+// padding (and `textfield` appearance).
+//
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+//
+// Define consistent border, margin, and padding.
+//
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+//
+// 1. Correct `color` not being inherited in IE 8/9.
+// 2. Remove padding so people aren't caught out if they zero out fieldsets.
+//
+
+legend {
+ border: 0; // 1
+ padding: 0; // 2
+}
+
+//
+// Remove default vertical scrollbar in IE 8/9.
+//
+
+textarea {
+ overflow: auto;
+}
+
+//
+// Don't inherit the `font-weight` (applied by a rule above).
+// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+//
+
+optgroup {
+ font-weight: bold;
+}
+
+// Tables
+// ==========================================================================
+
+//
+// Remove most spacing between table cells.
+//
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+td,
+th {
+ padding: 0;
+} \ No newline at end of file
diff --git a/bower_components/bootstrap/less/pager.less b/bower_components/bootstrap/less/pager.less
new file mode 100644
index 0000000..59103f4
--- /dev/null
+++ b/bower_components/bootstrap/less/pager.less
@@ -0,0 +1,55 @@
+//
+// Pager pagination
+// --------------------------------------------------
+
+
+.pager {
+ padding-left: 0;
+ margin: @line-height-computed 0;
+ list-style: none;
+ text-align: center;
+ &:extend(.clearfix all);
+ li {
+ display: inline;
+ > a,
+ > span {
+ display: inline-block;
+ padding: 5px 14px;
+ background-color: @pager-bg;
+ border: 1px solid @pager-border;
+ border-radius: @pager-border-radius;
+ }
+
+ > a:hover,
+ > a:focus {
+ text-decoration: none;
+ background-color: @pager-hover-bg;
+ }
+ }
+
+ .next {
+ > a,
+ > span {
+ float: right;
+ }
+ }
+
+ .previous {
+ > a,
+ > span {
+ float: left;
+ }
+ }
+
+ .disabled {
+ > a,
+ > a:hover,
+ > a:focus,
+ > span {
+ color: @pager-disabled-color;
+ background-color: @pager-bg;
+ cursor: not-allowed;
+ }
+ }
+
+}
diff --git a/bower_components/bootstrap/less/pagination.less b/bower_components/bootstrap/less/pagination.less
new file mode 100644
index 0000000..b2856ae
--- /dev/null
+++ b/bower_components/bootstrap/less/pagination.less
@@ -0,0 +1,88 @@
+//
+// Pagination (multiple pages)
+// --------------------------------------------------
+.pagination {
+ display: inline-block;
+ padding-left: 0;
+ margin: @line-height-computed 0;
+ border-radius: @border-radius-base;
+
+ > li {
+ display: inline; // Remove list-style and block-level defaults
+ > a,
+ > span {
+ position: relative;
+ float: left; // Collapse white-space
+ padding: @padding-base-vertical @padding-base-horizontal;
+ line-height: @line-height-base;
+ text-decoration: none;
+ color: @pagination-color;
+ background-color: @pagination-bg;
+ border: 1px solid @pagination-border;
+ margin-left: -1px;
+ }
+ &:first-child {
+ > a,
+ > span {
+ margin-left: 0;
+ .border-left-radius(@border-radius-base);
+ }
+ }
+ &:last-child {
+ > a,
+ > span {
+ .border-right-radius(@border-radius-base);
+ }
+ }
+ }
+
+ > li > a,
+ > li > span {
+ &:hover,
+ &:focus {
+ color: @pagination-hover-color;
+ background-color: @pagination-hover-bg;
+ border-color: @pagination-hover-border;
+ }
+ }
+
+ > .active > a,
+ > .active > span {
+ &,
+ &:hover,
+ &:focus {
+ z-index: 2;
+ color: @pagination-active-color;
+ background-color: @pagination-active-bg;
+ border-color: @pagination-active-border;
+ cursor: default;
+ }
+ }
+
+ > .disabled {
+ > span,
+ > span:hover,
+ > span:focus,
+ > a,
+ > a:hover,
+ > a:focus {
+ color: @pagination-disabled-color;
+ background-color: @pagination-disabled-bg;
+ border-color: @pagination-disabled-border;
+ cursor: not-allowed;
+ }
+ }
+}
+
+// Sizing
+// --------------------------------------------------
+
+// Large
+.pagination-lg {
+ .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);
+}
+
+// Small
+.pagination-sm {
+ .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);
+}
diff --git a/bower_components/bootstrap/less/panels.less b/bower_components/bootstrap/less/panels.less
new file mode 100644
index 0000000..20dd149
--- /dev/null
+++ b/bower_components/bootstrap/less/panels.less
@@ -0,0 +1,241 @@
+//
+// Panels
+// --------------------------------------------------
+
+
+// Base class
+.panel {
+ margin-bottom: @line-height-computed;
+ background-color: @panel-bg;
+ border: 1px solid transparent;
+ border-radius: @panel-border-radius;
+ .box-shadow(0 1px 1px rgba(0,0,0,.05));
+}
+
+// Panel contents
+.panel-body {
+ padding: @panel-body-padding;
+ &:extend(.clearfix all);
+}
+
+// Optional heading
+.panel-heading {
+ padding: 10px 15px;
+ border-bottom: 1px solid transparent;
+ .border-top-radius((@panel-border-radius - 1));
+
+ > .dropdown .dropdown-toggle {
+ color: inherit;
+ }
+}
+
+// Within heading, strip any `h*` tag of its default margins for spacing.
+.panel-title {
+ margin-top: 0;
+ margin-bottom: 0;
+ font-size: ceil((@font-size-base * 1.125));
+ color: inherit;
+
+ > a {
+ color: inherit;
+ }
+}
+
+// Optional footer (stays gray in every modifier class)
+.panel-footer {
+ padding: 10px 15px;
+ background-color: @panel-footer-bg;
+ border-top: 1px solid @panel-inner-border;
+ .border-bottom-radius((@panel-border-radius - 1));
+}
+
+
+// List groups in panels
+//
+// By default, space out list group content from panel headings to account for
+// any kind of custom content between the two.
+
+.panel {
+ > .list-group {
+ margin-bottom: 0;
+
+ .list-group-item {
+ border-width: 1px 0;
+ border-radius: 0;
+ }
+
+ // Add border top radius for first one
+ &:first-child {
+ .list-group-item:first-child {
+ border-top: 0;
+ .border-top-radius((@panel-border-radius - 1));
+ }
+ }
+ // Add border bottom radius for last one
+ &:last-child {
+ .list-group-item:last-child {
+ border-bottom: 0;
+ .border-bottom-radius((@panel-border-radius - 1));
+ }
+ }
+ }
+}
+// Collapse space between when there's no additional content.
+.panel-heading + .list-group {
+ .list-group-item:first-child {
+ border-top-width: 0;
+ }
+}
+
+
+// Tables in panels
+//
+// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and
+// watch it go full width.
+
+.panel {
+ > .table,
+ > .table-responsive > .table {
+ margin-bottom: 0;
+ }
+ // Add border top radius for first one
+ > .table:first-child,
+ > .table-responsive:first-child > .table:first-child {
+ .border-top-radius((@panel-border-radius - 1));
+
+ > thead:first-child,
+ > tbody:first-child {
+ > tr:first-child {
+ td:first-child,
+ th:first-child {
+ border-top-left-radius: (@panel-border-radius - 1);
+ }
+ td:last-child,
+ th:last-child {
+ border-top-right-radius: (@panel-border-radius - 1);
+ }
+ }
+ }
+ }
+ // Add border bottom radius for last one
+ > .table:last-child,
+ > .table-responsive:last-child > .table:last-child {
+ .border-bottom-radius((@panel-border-radius - 1));
+
+ > tbody:last-child,
+ > tfoot:last-child {
+ > tr:last-child {
+ td:first-child,
+ th:first-child {
+ border-bottom-left-radius: (@panel-border-radius - 1);
+ }
+ td:last-child,
+ th:last-child {
+ border-bottom-right-radius: (@panel-border-radius - 1);
+ }
+ }
+ }
+ }
+ > .panel-body + .table,
+ > .panel-body + .table-responsive {
+ border-top: 1px solid @table-border-color;
+ }
+ > .table > tbody:first-child > tr:first-child th,
+ > .table > tbody:first-child > tr:first-child td {
+ border-top: 0;
+ }
+ > .table-bordered,
+ > .table-responsive > .table-bordered {
+ border: 0;
+ > thead,
+ > tbody,
+ > tfoot {
+ > tr {
+ > th:first-child,
+ > td:first-child {
+ border-left: 0;
+ }
+ > th:last-child,
+ > td:last-child {
+ border-right: 0;
+ }
+ }
+ }
+ > thead,
+ > tbody {
+ > tr:first-child {
+ > td,
+ > th {
+ border-bottom: 0;
+ }
+ }
+ }
+ > tbody,
+ > tfoot {
+ > tr:last-child {
+ > td,
+ > th {
+ border-bottom: 0;
+ }
+ }
+ }
+ }
+ > .table-responsive {
+ border: 0;
+ margin-bottom: 0;
+ }
+}
+
+
+// Collapsable panels (aka, accordion)
+//
+// Wrap a series of panels in `.panel-group` to turn them into an accordion with
+// the help of our collapse JavaScript plugin.
+
+.panel-group {
+ margin-bottom: @line-height-computed;
+
+ // Tighten up margin so it's only between panels
+ .panel {
+ margin-bottom: 0;
+ border-radius: @panel-border-radius;
+ overflow: hidden; // crop contents when collapsed
+ + .panel {
+ margin-top: 5px;
+ }
+ }
+
+ .panel-heading {
+ border-bottom: 0;
+ + .panel-collapse .panel-body {
+ border-top: 1px solid @panel-inner-border;
+ }
+ }
+ .panel-footer {
+ border-top: 0;
+ + .panel-collapse .panel-body {
+ border-bottom: 1px solid @panel-inner-border;
+ }
+ }
+}
+
+
+// Contextual variations
+.panel-default {
+ .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);
+}
+.panel-primary {
+ .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);
+}
+.panel-success {
+ .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);
+}
+.panel-info {
+ .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);
+}
+.panel-warning {
+ .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);
+}
+.panel-danger {
+ .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);
+}
diff --git a/bower_components/bootstrap/less/popovers.less b/bower_components/bootstrap/less/popovers.less
new file mode 100644
index 0000000..696d74c
--- /dev/null
+++ b/bower_components/bootstrap/less/popovers.less
@@ -0,0 +1,133 @@
+//
+// Popovers
+// --------------------------------------------------
+
+
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: @zindex-popover;
+ display: none;
+ max-width: @popover-max-width;
+ padding: 1px;
+ text-align: left; // Reset given new insertion method
+ background-color: @popover-bg;
+ background-clip: padding-box;
+ border: 1px solid @popover-fallback-border-color;
+ border: 1px solid @popover-border-color;
+ border-radius: @border-radius-large;
+ .box-shadow(0 5px 10px rgba(0,0,0,.2));
+
+ // Overrides for proper insertion
+ white-space: normal;
+
+ // Offset the popover to account for the popover arrow
+ &.top { margin-top: -@popover-arrow-width; }
+ &.right { margin-left: @popover-arrow-width; }
+ &.bottom { margin-top: @popover-arrow-width; }
+ &.left { margin-left: -@popover-arrow-width; }
+}
+
+.popover-title {
+ margin: 0; // reset heading margin
+ padding: 8px 14px;
+ font-size: @font-size-base;
+ font-weight: normal;
+ line-height: 18px;
+ background-color: @popover-title-bg;
+ border-bottom: 1px solid darken(@popover-title-bg, 5%);
+ border-radius: 5px 5px 0 0;
+}
+
+.popover-content {
+ padding: 9px 14px;
+}
+
+// Arrows
+//
+// .arrow is outer, .arrow:after is inner
+
+.popover > .arrow {
+ &,
+ &:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+ }
+}
+.popover > .arrow {
+ border-width: @popover-arrow-outer-width;
+}
+.popover > .arrow:after {
+ border-width: @popover-arrow-width;
+ content: "";
+}
+
+.popover {
+ &.top > .arrow {
+ left: 50%;
+ margin-left: -@popover-arrow-outer-width;
+ border-bottom-width: 0;
+ border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback
+ border-top-color: @popover-arrow-outer-color;
+ bottom: -@popover-arrow-outer-width;
+ &:after {
+ content: " ";
+ bottom: 1px;
+ margin-left: -@popover-arrow-width;
+ border-bottom-width: 0;
+ border-top-color: @popover-arrow-color;
+ }
+ }
+ &.right > .arrow {
+ top: 50%;
+ left: -@popover-arrow-outer-width;
+ margin-top: -@popover-arrow-outer-width;
+ border-left-width: 0;
+ border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback
+ border-right-color: @popover-arrow-outer-color;
+ &:after {
+ content: " ";
+ left: 1px;
+ bottom: -@popover-arrow-width;
+ border-left-width: 0;
+ border-right-color: @popover-arrow-color;
+ }
+ }
+ &.bottom > .arrow {
+ left: 50%;
+ margin-left: -@popover-arrow-outer-width;
+ border-top-width: 0;
+ border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback
+ border-bottom-color: @popover-arrow-outer-color;
+ top: -@popover-arrow-outer-width;
+ &:after {
+ content: " ";
+ top: 1px;
+ margin-left: -@popover-arrow-width;
+ border-top-width: 0;
+ border-bottom-color: @popover-arrow-color;
+ }
+ }
+
+ &.left > .arrow {
+ top: 50%;
+ right: -@popover-arrow-outer-width;
+ margin-top: -@popover-arrow-outer-width;
+ border-right-width: 0;
+ border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback
+ border-left-color: @popover-arrow-outer-color;
+ &:after {
+ content: " ";
+ right: 1px;
+ border-right-width: 0;
+ border-left-color: @popover-arrow-color;
+ bottom: -@popover-arrow-width;
+ }
+ }
+
+}
diff --git a/bower_components/bootstrap/less/print.less b/bower_components/bootstrap/less/print.less
new file mode 100644
index 0000000..3655d03
--- /dev/null
+++ b/bower_components/bootstrap/less/print.less
@@ -0,0 +1,101 @@
+//
+// Basic print styles
+// --------------------------------------------------
+// Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css
+
+@media print {
+
+ * {
+ text-shadow: none !important;
+ color: #000 !important; // Black prints faster: h5bp.com/s
+ background: transparent !important;
+ box-shadow: none !important;
+ }
+
+ a,
+ a:visited {
+ text-decoration: underline;
+ }
+
+ a[href]:after {
+ content: " (" attr(href) ")";
+ }
+
+ abbr[title]:after {
+ content: " (" attr(title) ")";
+ }
+
+ // Don't show links for images, or javascript/internal links
+ a[href^="javascript:"]:after,
+ a[href^="#"]:after {
+ content: "";
+ }
+
+ pre,
+ blockquote {
+ border: 1px solid #999;
+ page-break-inside: avoid;
+ }
+
+ thead {
+ display: table-header-group; // h5bp.com/t
+ }
+
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+
+ img {
+ max-width: 100% !important;
+ }
+
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+
+ // Chrome (OSX) fix for https://github.com/twbs/bootstrap/issues/11245
+ // Once fixed, we can just straight up remove this.
+ select {
+ background: #fff !important;
+ }
+
+ // Bootstrap components
+ .navbar {
+ display: none;
+ }
+ .table {
+ td,
+ th {
+ background-color: #fff !important;
+ }
+ }
+ .btn,
+ .dropup > .btn {
+ > .caret {
+ border-top-color: #000 !important;
+ }
+ }
+ .label {
+ border: 1px solid #000;
+ }
+
+ .table {
+ border-collapse: collapse !important;
+ }
+ .table-bordered {
+ th,
+ td {
+ border: 1px solid #ddd !important;
+ }
+ }
+
+}
diff --git a/bower_components/bootstrap/less/progress-bars.less b/bower_components/bootstrap/less/progress-bars.less
new file mode 100644
index 0000000..76c87be
--- /dev/null
+++ b/bower_components/bootstrap/less/progress-bars.less
@@ -0,0 +1,80 @@
+//
+// Progress bars
+// --------------------------------------------------
+
+
+// Bar animations
+// -------------------------
+
+// WebKit
+@-webkit-keyframes progress-bar-stripes {
+ from { background-position: 40px 0; }
+ to { background-position: 0 0; }
+}
+
+// Spec and IE10+
+@keyframes progress-bar-stripes {
+ from { background-position: 40px 0; }
+ to { background-position: 0 0; }
+}
+
+
+
+// Bar itself
+// -------------------------
+
+// Outer container
+.progress {
+ overflow: hidden;
+ height: @line-height-computed;
+ margin-bottom: @line-height-computed;
+ background-color: @progress-bg;
+ border-radius: @border-radius-base;
+ .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
+}
+
+// Bar of progress
+.progress-bar {
+ float: left;
+ width: 0%;
+ height: 100%;
+ font-size: @font-size-small;
+ line-height: @line-height-computed;
+ color: @progress-bar-color;
+ text-align: center;
+ background-color: @progress-bar-bg;
+ .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));
+ .transition(width .6s ease);
+}
+
+// Striped bars
+.progress-striped .progress-bar {
+ #gradient > .striped();
+ background-size: 40px 40px;
+}
+
+// Call animation for the active one
+.progress.active .progress-bar {
+ .animation(progress-bar-stripes 2s linear infinite);
+}
+
+
+
+// Variations
+// -------------------------
+
+.progress-bar-success {
+ .progress-bar-variant(@progress-bar-success-bg);
+}
+
+.progress-bar-info {
+ .progress-bar-variant(@progress-bar-info-bg);
+}
+
+.progress-bar-warning {
+ .progress-bar-variant(@progress-bar-warning-bg);
+}
+
+.progress-bar-danger {
+ .progress-bar-variant(@progress-bar-danger-bg);
+}
diff --git a/bower_components/bootstrap/less/responsive-utilities.less b/bower_components/bootstrap/less/responsive-utilities.less
new file mode 100644
index 0000000..027a264
--- /dev/null
+++ b/bower_components/bootstrap/less/responsive-utilities.less
@@ -0,0 +1,92 @@
+//
+// Responsive: Utility classes
+// --------------------------------------------------
+
+
+// IE10 in Windows (Phone) 8
+//
+// Support for responsive views via media queries is kind of borked in IE10, for
+// Surface/desktop in split view and for Windows Phone 8. This particular fix
+// must be accompanied by a snippet of JavaScript to sniff the user agent and
+// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at
+// our Getting Started page for more information on this bug.
+//
+// For more information, see the following:
+//
+// Issue: https://github.com/twbs/bootstrap/issues/10497
+// Docs: http://getbootstrap.com/getting-started/#browsers
+// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/
+
+@-ms-viewport {
+ width: device-width;
+}
+
+
+// Visibility utilities
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+ .responsive-invisibility();
+}
+
+.visible-xs {
+ @media (max-width: @screen-xs-max) {
+ .responsive-visibility();
+ }
+}
+.visible-sm {
+ @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {
+ .responsive-visibility();
+ }
+}
+.visible-md {
+ @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {
+ .responsive-visibility();
+ }
+}
+.visible-lg {
+ @media (min-width: @screen-lg-min) {
+ .responsive-visibility();
+ }
+}
+
+.hidden-xs {
+ @media (max-width: @screen-xs-max) {
+ .responsive-invisibility();
+ }
+}
+.hidden-sm {
+ @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {
+ .responsive-invisibility();
+ }
+}
+.hidden-md {
+ @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {
+ .responsive-invisibility();
+ }
+}
+.hidden-lg {
+ @media (min-width: @screen-lg-min) {
+ .responsive-invisibility();
+ }
+}
+
+
+// Print utilities
+//
+// Media queries are placed on the inside to be mixin-friendly.
+
+.visible-print {
+ .responsive-invisibility();
+
+ @media print {
+ .responsive-visibility();
+ }
+}
+
+.hidden-print {
+ @media print {
+ .responsive-invisibility();
+ }
+}
diff --git a/bower_components/bootstrap/less/scaffolding.less b/bower_components/bootstrap/less/scaffolding.less
new file mode 100644
index 0000000..fe29f2d
--- /dev/null
+++ b/bower_components/bootstrap/less/scaffolding.less
@@ -0,0 +1,134 @@
+//
+// Scaffolding
+// --------------------------------------------------
+
+
+// Reset the box-sizing
+//
+// Heads up! This reset may cause conflicts with some third-party widgets.
+// For recommendations on resolving such conflicts, see
+// http://getbootstrap.com/getting-started/#third-box-sizing
+* {
+ .box-sizing(border-box);
+}
+*:before,
+*:after {
+ .box-sizing(border-box);
+}
+
+
+// Body reset
+
+html {
+ font-size: 62.5%;
+ -webkit-tap-highlight-color: rgba(0,0,0,0);
+}
+
+body {
+ font-family: @font-family-base;
+ font-size: @font-size-base;
+ line-height: @line-height-base;
+ color: @text-color;
+ background-color: @body-bg;
+}
+
+// Reset fonts for relevant elements
+input,
+button,
+select,
+textarea {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+
+
+// Links
+
+a {
+ color: @link-color;
+ text-decoration: none;
+
+ &:hover,
+ &:focus {
+ color: @link-hover-color;
+ text-decoration: underline;
+ }
+
+ &:focus {
+ .tab-focus();
+ }
+}
+
+
+// Figures
+//
+// We reset this here because previously Normalize had no `figure` margins. This
+// ensures we don't break anyone's use of the element.
+
+figure {
+ margin: 0;
+}
+
+
+// Images
+
+img {
+ vertical-align: middle;
+}
+
+// Responsive images (ensure images don't scale beyond their parents)
+.img-responsive {
+ .img-responsive();
+}
+
+// Rounded corners
+.img-rounded {
+ border-radius: @border-radius-large;
+}
+
+// Image thumbnails
+//
+// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.
+.img-thumbnail {
+ padding: @thumbnail-padding;
+ line-height: @line-height-base;
+ background-color: @thumbnail-bg;
+ border: 1px solid @thumbnail-border;
+ border-radius: @thumbnail-border-radius;
+ .transition(all .2s ease-in-out);
+
+ // Keep them at most 100% wide
+ .img-responsive(inline-block);
+}
+
+// Perfect circle
+.img-circle {
+ border-radius: 50%; // set radius in percents
+}
+
+
+// Horizontal rules
+
+hr {
+ margin-top: @line-height-computed;
+ margin-bottom: @line-height-computed;
+ border: 0;
+ border-top: 1px solid @hr-border;
+}
+
+
+// Only display content to screen readers
+//
+// See: http://a11yproject.com/posts/how-to-hide-content/
+
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ margin: -1px;
+ padding: 0;
+ overflow: hidden;
+ clip: rect(0,0,0,0);
+ border: 0;
+}
diff --git a/bower_components/bootstrap/less/tables.less b/bower_components/bootstrap/less/tables.less
new file mode 100644
index 0000000..c41989c
--- /dev/null
+++ b/bower_components/bootstrap/less/tables.less
@@ -0,0 +1,233 @@
+//
+// Tables
+// --------------------------------------------------
+
+
+table {
+ max-width: 100%;
+ background-color: @table-bg;
+}
+th {
+ text-align: left;
+}
+
+
+// Baseline styles
+
+.table {
+ width: 100%;
+ margin-bottom: @line-height-computed;
+ // Cells
+ > thead,
+ > tbody,
+ > tfoot {
+ > tr {
+ > th,
+ > td {
+ padding: @table-cell-padding;
+ line-height: @line-height-base;
+ vertical-align: top;
+ border-top: 1px solid @table-border-color;
+ }
+ }
+ }
+ // Bottom align for column headings
+ > thead > tr > th {
+ vertical-align: bottom;
+ border-bottom: 2px solid @table-border-color;
+ }
+ // Remove top border from thead by default
+ > caption + thead,
+ > colgroup + thead,
+ > thead:first-child {
+ > tr:first-child {
+ > th,
+ > td {
+ border-top: 0;
+ }
+ }
+ }
+ // Account for multiple tbody instances
+ > tbody + tbody {
+ border-top: 2px solid @table-border-color;
+ }
+
+ // Nesting
+ .table {
+ background-color: @body-bg;
+ }
+}
+
+
+// Condensed table w/ half padding
+
+.table-condensed {
+ > thead,
+ > tbody,
+ > tfoot {
+ > tr {
+ > th,
+ > td {
+ padding: @table-condensed-cell-padding;
+ }
+ }
+ }
+}
+
+
+// Bordered version
+//
+// Add borders all around the table and between all the columns.
+
+.table-bordered {
+ border: 1px solid @table-border-color;
+ > thead,
+ > tbody,
+ > tfoot {
+ > tr {
+ > th,
+ > td {
+ border: 1px solid @table-border-color;
+ }
+ }
+ }
+ > thead > tr {
+ > th,
+ > td {
+ border-bottom-width: 2px;
+ }
+ }
+}
+
+
+// Zebra-striping
+//
+// Default zebra-stripe styles (alternating gray and transparent backgrounds)
+
+.table-striped {
+ > tbody > tr:nth-child(odd) {
+ > td,
+ > th {
+ background-color: @table-bg-accent;
+ }
+ }
+}
+
+
+// Hover effect
+//
+// Placed here since it has to come after the potential zebra striping
+
+.table-hover {
+ > tbody > tr:hover {
+ > td,
+ > th {
+ background-color: @table-bg-hover;
+ }
+ }
+}
+
+
+// Table cell sizing
+//
+// Reset default table behavior
+
+table col[class*="col-"] {
+ position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)
+ float: none;
+ display: table-column;
+}
+table {
+ td,
+ th {
+ &[class*="col-"] {
+ position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)
+ float: none;
+ display: table-cell;
+ }
+ }
+}
+
+
+// Table backgrounds
+//
+// Exact selectors below required to override `.table-striped` and prevent
+// inheritance to nested tables.
+
+// Generate the contextual variants
+.table-row-variant(active; @table-bg-active);
+.table-row-variant(success; @state-success-bg);
+.table-row-variant(info; @state-info-bg);
+.table-row-variant(warning; @state-warning-bg);
+.table-row-variant(danger; @state-danger-bg);
+
+
+// Responsive tables
+//
+// Wrap your tables in `.table-responsive` and we'll make them mobile friendly
+// by enabling horizontal scrolling. Only applies <768px. Everything above that
+// will display normally.
+
+@media (max-width: @screen-xs-max) {
+ .table-responsive {
+ width: 100%;
+ margin-bottom: (@line-height-computed * 0.75);
+ overflow-y: hidden;
+ overflow-x: scroll;
+ -ms-overflow-style: -ms-autohiding-scrollbar;
+ border: 1px solid @table-border-color;
+ -webkit-overflow-scrolling: touch;
+
+ // Tighten up spacing
+ > .table {
+ margin-bottom: 0;
+
+ // Ensure the content doesn't wrap
+ > thead,
+ > tbody,
+ > tfoot {
+ > tr {
+ > th,
+ > td {
+ white-space: nowrap;
+ }
+ }
+ }
+ }
+
+ // Special overrides for the bordered tables
+ > .table-bordered {
+ border: 0;
+
+ // Nuke the appropriate borders so that the parent can handle them
+ > thead,
+ > tbody,
+ > tfoot {
+ > tr {
+ > th:first-child,
+ > td:first-child {
+ border-left: 0;
+ }
+ > th:last-child,
+ > td:last-child {
+ border-right: 0;
+ }
+ }
+ }
+
+ // Only nuke the last row's bottom-border in `tbody` and `tfoot` since
+ // chances are there will be only one `tr` in a `thead` and that would
+ // remove the border altogether.
+ > tbody,
+ > tfoot {
+ > tr:last-child {
+ > th,
+ > td {
+ border-bottom: 0;
+ }
+ }
+ }
+
+ }
+ }
+}
diff --git a/bower_components/bootstrap/less/theme.less b/bower_components/bootstrap/less/theme.less
new file mode 100644
index 0000000..6f957fb
--- /dev/null
+++ b/bower_components/bootstrap/less/theme.less
@@ -0,0 +1,247 @@
+
+//
+// Load core variables and mixins
+// --------------------------------------------------
+
+@import "variables.less";
+@import "mixins.less";
+
+
+
+//
+// Buttons
+// --------------------------------------------------
+
+// Common styles
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+ text-shadow: 0 -1px 0 rgba(0,0,0,.2);
+ @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);
+ .box-shadow(@shadow);
+
+ // Reset the shadow
+ &:active,
+ &.active {
+ .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
+ }
+}
+
+// Mixin for generating new styles
+.btn-styles(@btn-color: #555) {
+ #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));
+ .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners
+ background-repeat: repeat-x;
+ border-color: darken(@btn-color, 14%);
+
+ &:hover,
+ &:focus {
+ background-color: darken(@btn-color, 12%);
+ background-position: 0 -15px;
+ }
+
+ &:active,
+ &.active {
+ background-color: darken(@btn-color, 12%);
+ border-color: darken(@btn-color, 14%);
+ }
+}
+
+// Common styles
+.btn {
+ // Remove the gradient for the pressed/active state
+ &:active,
+ &.active {
+ background-image: none;
+ }
+}
+
+// Apply the mixin to the buttons
+.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }
+.btn-primary { .btn-styles(@btn-primary-bg); }
+.btn-success { .btn-styles(@btn-success-bg); }
+.btn-info { .btn-styles(@btn-info-bg); }
+.btn-warning { .btn-styles(@btn-warning-bg); }
+.btn-danger { .btn-styles(@btn-danger-bg); }
+
+
+
+//
+// Images
+// --------------------------------------------------
+
+.thumbnail,
+.img-thumbnail {
+ .box-shadow(0 1px 2px rgba(0,0,0,.075));
+}
+
+
+
+//
+// Dropdowns
+// --------------------------------------------------
+
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));
+ background-color: darken(@dropdown-link-hover-bg, 5%);
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));
+ background-color: darken(@dropdown-link-active-bg, 5%);
+}
+
+
+
+//
+// Navbar
+// --------------------------------------------------
+
+// Default navbar
+.navbar-default {
+ #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);
+ .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered
+ border-radius: @navbar-border-radius;
+ @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);
+ .box-shadow(@shadow);
+
+ .navbar-nav > .active > a {
+ #gradient > .vertical(@start-color: darken(@navbar-default-bg, 5%); @end-color: darken(@navbar-default-bg, 2%));
+ .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));
+ }
+}
+.navbar-brand,
+.navbar-nav > li > a {
+ text-shadow: 0 1px 0 rgba(255,255,255,.25);
+}
+
+// Inverted navbar
+.navbar-inverse {
+ #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);
+ .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered
+
+ .navbar-nav > .active > a {
+ #gradient > .vertical(@start-color: @navbar-inverse-bg; @end-color: lighten(@navbar-inverse-bg, 2.5%));
+ .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));
+ }
+
+ .navbar-brand,
+ .navbar-nav > li > a {
+ text-shadow: 0 -1px 0 rgba(0,0,0,.25);
+ }
+}
+
+// Undo rounded corners in static and fixed navbars
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ border-radius: 0;
+}
+
+
+
+//
+// Alerts
+// --------------------------------------------------
+
+// Common styles
+.alert {
+ text-shadow: 0 1px 0 rgba(255,255,255,.2);
+ @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);
+ .box-shadow(@shadow);
+}
+
+// Mixin for generating new styles
+.alert-styles(@color) {
+ #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));
+ border-color: darken(@color, 15%);
+}
+
+// Apply the mixin to the alerts
+.alert-success { .alert-styles(@alert-success-bg); }
+.alert-info { .alert-styles(@alert-info-bg); }
+.alert-warning { .alert-styles(@alert-warning-bg); }
+.alert-danger { .alert-styles(@alert-danger-bg); }
+
+
+
+//
+// Progress bars
+// --------------------------------------------------
+
+// Give the progress background some depth
+.progress {
+ #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)
+}
+
+// Mixin for generating new styles
+.progress-bar-styles(@color) {
+ #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));
+}
+
+// Apply the mixin to the progress bars
+.progress-bar { .progress-bar-styles(@progress-bar-bg); }
+.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }
+.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }
+.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }
+.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }
+
+
+
+//
+// List groups
+// --------------------------------------------------
+
+.list-group {
+ border-radius: @border-radius-base;
+ .box-shadow(0 1px 2px rgba(0,0,0,.075));
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);
+ #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));
+ border-color: darken(@list-group-active-border, 7.5%);
+}
+
+
+
+//
+// Panels
+// --------------------------------------------------
+
+// Common styles
+.panel {
+ .box-shadow(0 1px 2px rgba(0,0,0,.05));
+}
+
+// Mixin for generating new styles
+.panel-heading-styles(@color) {
+ #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));
+}
+
+// Apply the mixin to the panel headings only
+.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }
+.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }
+.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }
+.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }
+.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }
+.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }
+
+
+
+//
+// Wells
+// --------------------------------------------------
+
+.well {
+ #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);
+ border-color: darken(@well-bg, 10%);
+ @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);
+ .box-shadow(@shadow);
+}
diff --git a/bower_components/bootstrap/less/thumbnails.less b/bower_components/bootstrap/less/thumbnails.less
new file mode 100644
index 0000000..c428920
--- /dev/null
+++ b/bower_components/bootstrap/less/thumbnails.less
@@ -0,0 +1,36 @@
+//
+// Thumbnails
+// --------------------------------------------------
+
+
+// Mixin and adjust the regular image class
+.thumbnail {
+ display: block;
+ padding: @thumbnail-padding;
+ margin-bottom: @line-height-computed;
+ line-height: @line-height-base;
+ background-color: @thumbnail-bg;
+ border: 1px solid @thumbnail-border;
+ border-radius: @thumbnail-border-radius;
+ .transition(all .2s ease-in-out);
+
+ > img,
+ a > img {
+ &:extend(.img-responsive);
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ // Add a hover state for linked versions only
+ a&:hover,
+ a&:focus,
+ a&.active {
+ border-color: @link-color;
+ }
+
+ // Image captions
+ .caption {
+ padding: @thumbnail-caption-padding;
+ color: @thumbnail-caption-color;
+ }
+}
diff --git a/bower_components/bootstrap/less/tooltip.less b/bower_components/bootstrap/less/tooltip.less
new file mode 100644
index 0000000..bd62699
--- /dev/null
+++ b/bower_components/bootstrap/less/tooltip.less
@@ -0,0 +1,95 @@
+//
+// Tooltips
+// --------------------------------------------------
+
+
+// Base class
+.tooltip {
+ position: absolute;
+ z-index: @zindex-tooltip;
+ display: block;
+ visibility: visible;
+ font-size: @font-size-small;
+ line-height: 1.4;
+ .opacity(0);
+
+ &.in { .opacity(@tooltip-opacity); }
+ &.top { margin-top: -3px; padding: @tooltip-arrow-width 0; }
+ &.right { margin-left: 3px; padding: 0 @tooltip-arrow-width; }
+ &.bottom { margin-top: 3px; padding: @tooltip-arrow-width 0; }
+ &.left { margin-left: -3px; padding: 0 @tooltip-arrow-width; }
+}
+
+// Wrapper for the tooltip content
+.tooltip-inner {
+ max-width: @tooltip-max-width;
+ padding: 3px 8px;
+ color: @tooltip-color;
+ text-align: center;
+ text-decoration: none;
+ background-color: @tooltip-bg;
+ border-radius: @border-radius-base;
+}
+
+// Arrows
+.tooltip-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.tooltip {
+ &.top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -@tooltip-arrow-width;
+ border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
+ border-top-color: @tooltip-arrow-color;
+ }
+ &.top-left .tooltip-arrow {
+ bottom: 0;
+ left: @tooltip-arrow-width;
+ border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
+ border-top-color: @tooltip-arrow-color;
+ }
+ &.top-right .tooltip-arrow {
+ bottom: 0;
+ right: @tooltip-arrow-width;
+ border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
+ border-top-color: @tooltip-arrow-color;
+ }
+ &.right .tooltip-arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -@tooltip-arrow-width;
+ border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;
+ border-right-color: @tooltip-arrow-color;
+ }
+ &.left .tooltip-arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -@tooltip-arrow-width;
+ border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;
+ border-left-color: @tooltip-arrow-color;
+ }
+ &.bottom .tooltip-arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -@tooltip-arrow-width;
+ border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
+ border-bottom-color: @tooltip-arrow-color;
+ }
+ &.bottom-left .tooltip-arrow {
+ top: 0;
+ left: @tooltip-arrow-width;
+ border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
+ border-bottom-color: @tooltip-arrow-color;
+ }
+ &.bottom-right .tooltip-arrow {
+ top: 0;
+ right: @tooltip-arrow-width;
+ border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
+ border-bottom-color: @tooltip-arrow-color;
+ }
+}
diff --git a/bower_components/bootstrap/less/type.less b/bower_components/bootstrap/less/type.less
new file mode 100644
index 0000000..5e2a219
--- /dev/null
+++ b/bower_components/bootstrap/less/type.less
@@ -0,0 +1,293 @@
+//
+// Typography
+// --------------------------------------------------
+
+
+// Headings
+// -------------------------
+
+h1, h2, h3, h4, h5, h6,
+.h1, .h2, .h3, .h4, .h5, .h6 {
+ font-family: @headings-font-family;
+ font-weight: @headings-font-weight;
+ line-height: @headings-line-height;
+ color: @headings-color;
+
+ small,
+ .small {
+ font-weight: normal;
+ line-height: 1;
+ color: @headings-small-color;
+ }
+}
+
+h1, .h1,
+h2, .h2,
+h3, .h3 {
+ margin-top: @line-height-computed;
+ margin-bottom: (@line-height-computed / 2);
+
+ small,
+ .small {
+ font-size: 65%;
+ }
+}
+h4, .h4,
+h5, .h5,
+h6, .h6 {
+ margin-top: (@line-height-computed / 2);
+ margin-bottom: (@line-height-computed / 2);
+
+ small,
+ .small {
+ font-size: 75%;
+ }
+}
+
+h1, .h1 { font-size: @font-size-h1; }
+h2, .h2 { font-size: @font-size-h2; }
+h3, .h3 { font-size: @font-size-h3; }
+h4, .h4 { font-size: @font-size-h4; }
+h5, .h5 { font-size: @font-size-h5; }
+h6, .h6 { font-size: @font-size-h6; }
+
+
+// Body text
+// -------------------------
+
+p {
+ margin: 0 0 (@line-height-computed / 2);
+}
+
+.lead {
+ margin-bottom: @line-height-computed;
+ font-size: floor((@font-size-base * 1.15));
+ font-weight: 200;
+ line-height: 1.4;
+
+ @media (min-width: @screen-sm-min) {
+ font-size: (@font-size-base * 1.5);
+ }
+}
+
+
+// Emphasis & misc
+// -------------------------
+
+// Ex: 14px base font * 85% = about 12px
+small,
+.small { font-size: 85%; }
+
+// Undo browser default styling
+cite { font-style: normal; }
+
+// Alignment
+.text-left { text-align: left; }
+.text-right { text-align: right; }
+.text-center { text-align: center; }
+.text-justify { text-align: justify; }
+
+// Contextual colors
+.text-muted {
+ color: @text-muted;
+}
+.text-primary {
+ .text-emphasis-variant(@brand-primary);
+}
+.text-success {
+ .text-emphasis-variant(@state-success-text);
+}
+.text-info {
+ .text-emphasis-variant(@state-info-text);
+}
+.text-warning {
+ .text-emphasis-variant(@state-warning-text);
+}
+.text-danger {
+ .text-emphasis-variant(@state-danger-text);
+}
+
+// Contextual backgrounds
+// For now we'll leave these alongside the text classes until v4 when we can
+// safely shift things around (per SemVer rules).
+.bg-primary {
+ // Given the contrast here, this is the only class to have its color inverted
+ // automatically.
+ color: #fff;
+ .bg-variant(@brand-primary);
+}
+.bg-success {
+ .bg-variant(@state-success-bg);
+}
+.bg-info {
+ .bg-variant(@state-info-bg);
+}
+.bg-warning {
+ .bg-variant(@state-warning-bg);
+}
+.bg-danger {
+ .bg-variant(@state-danger-bg);
+}
+
+
+// Page header
+// -------------------------
+
+.page-header {
+ padding-bottom: ((@line-height-computed / 2) - 1);
+ margin: (@line-height-computed * 2) 0 @line-height-computed;
+ border-bottom: 1px solid @page-header-border-color;
+}
+
+
+// Lists
+// --------------------------------------------------
+
+// Unordered and Ordered lists
+ul,
+ol {
+ margin-top: 0;
+ margin-bottom: (@line-height-computed / 2);
+ ul,
+ ol {
+ margin-bottom: 0;
+ }
+}
+
+// List options
+
+// Unstyled keeps list items block level, just removes default browser padding and list-style
+.list-unstyled {
+ padding-left: 0;
+ list-style: none;
+}
+
+// Inline turns list items into inline-block
+.list-inline {
+ .list-unstyled();
+ margin-left: -5px;
+
+ > li {
+ display: inline-block;
+ padding-left: 5px;
+ padding-right: 5px;
+ }
+}
+
+// Description Lists
+dl {
+ margin-top: 0; // Remove browser default
+ margin-bottom: @line-height-computed;
+}
+dt,
+dd {
+ line-height: @line-height-base;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-left: 0; // Undo browser default
+}
+
+// Horizontal description lists
+//
+// Defaults to being stacked without any of the below styles applied, until the
+// grid breakpoint is reached (default of ~768px).
+
+@media (min-width: @grid-float-breakpoint) {
+ .dl-horizontal {
+ dt {
+ float: left;
+ width: (@component-offset-horizontal - 20);
+ clear: left;
+ text-align: right;
+ .text-overflow();
+ }
+ dd {
+ margin-left: @component-offset-horizontal;
+ &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present
+ }
+ }
+}
+
+// MISC
+// ----
+
+// Abbreviations and acronyms
+abbr[title],
+// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257
+abbr[data-original-title] {
+ cursor: help;
+ border-bottom: 1px dotted @abbr-border-color;
+}
+.initialism {
+ font-size: 90%;
+ text-transform: uppercase;
+}
+
+// Blockquotes
+blockquote {
+ padding: (@line-height-computed / 2) @line-height-computed;
+ margin: 0 0 @line-height-computed;
+ font-size: @blockquote-font-size;
+ border-left: 5px solid @blockquote-border-color;
+
+ p,
+ ul,
+ ol {
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+
+ // Note: Deprecated small and .small as of v3.1.0
+ // Context: https://github.com/twbs/bootstrap/issues/11660
+ footer,
+ small,
+ .small {
+ display: block;
+ font-size: 80%; // back to default font-size
+ line-height: @line-height-base;
+ color: @blockquote-small-color;
+
+ &:before {
+ content: '\2014 \00A0'; // em dash, nbsp
+ }
+ }
+}
+
+// Opposite alignment of blockquote
+//
+// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.
+.blockquote-reverse,
+blockquote.pull-right {
+ padding-right: 15px;
+ padding-left: 0;
+ border-right: 5px solid @blockquote-border-color;
+ border-left: 0;
+ text-align: right;
+
+ // Account for citation
+ footer,
+ small,
+ .small {
+ &:before { content: ''; }
+ &:after {
+ content: '\00A0 \2014'; // nbsp, em dash
+ }
+ }
+}
+
+// Quotes
+blockquote:before,
+blockquote:after {
+ content: "";
+}
+
+// Addresses
+address {
+ margin-bottom: @line-height-computed;
+ font-style: normal;
+ line-height: @line-height-base;
+}
diff --git a/bower_components/bootstrap/less/utilities.less b/bower_components/bootstrap/less/utilities.less
new file mode 100644
index 0000000..a260312
--- /dev/null
+++ b/bower_components/bootstrap/less/utilities.less
@@ -0,0 +1,56 @@
+//
+// Utility classes
+// --------------------------------------------------
+
+
+// Floats
+// -------------------------
+
+.clearfix {
+ .clearfix();
+}
+.center-block {
+ .center-block();
+}
+.pull-right {
+ float: right !important;
+}
+.pull-left {
+ float: left !important;
+}
+
+
+// Toggling content
+// -------------------------
+
+// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1
+.hide {
+ display: none !important;
+}
+.show {
+ display: block !important;
+}
+.invisible {
+ visibility: hidden;
+}
+.text-hide {
+ .text-hide();
+}
+
+
+// Hide from screenreaders and browsers
+//
+// Credit: HTML5 Boilerplate
+
+.hidden {
+ display: none !important;
+ visibility: hidden !important;
+}
+
+
+// For Affix plugin
+// -------------------------
+
+.affix {
+ position: fixed;
+}
diff --git a/bower_components/bootstrap/less/variables.less b/bower_components/bootstrap/less/variables.less
new file mode 100644
index 0000000..3846adc
--- /dev/null
+++ b/bower_components/bootstrap/less/variables.less
@@ -0,0 +1,829 @@
+//
+// Variables
+// --------------------------------------------------
+
+
+//== Colors
+//
+//## Gray and brand colors for use across Bootstrap.
+
+@gray-darker: lighten(#000, 13.5%); // #222
+@gray-dark: lighten(#000, 20%); // #333
+@gray: lighten(#000, 33.5%); // #555
+@gray-light: lighten(#000, 60%); // #999
+@gray-lighter: lighten(#000, 93.5%); // #eee
+
+@brand-primary: #428bca;
+@brand-success: #5cb85c;
+@brand-info: #5bc0de;
+@brand-warning: #f0ad4e;
+@brand-danger: #d9534f;
+
+
+//== Scaffolding
+//
+// ## Settings for some of the most global styles.
+
+//** Background color for `<body>`.
+@body-bg: #fff;
+//** Global text color on `<body>`.
+@text-color: @gray-dark;
+
+//** Global textual link color.
+@link-color: @brand-primary;
+//** Link hover color set via `darken()` function.
+@link-hover-color: darken(@link-color, 15%);
+
+
+//== Typography
+//
+//## Font, line-height, and color for body text, headings, and more.
+
+@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif;
+@font-family-serif: Georgia, "Times New Roman", Times, serif;
+//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
+@font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
+@font-family-base: @font-family-sans-serif;
+
+@font-size-base: 14px;
+@font-size-large: ceil((@font-size-base * 1.25)); // ~18px
+@font-size-small: ceil((@font-size-base * 0.85)); // ~12px
+
+@font-size-h1: floor((@font-size-base * 2.6)); // ~36px
+@font-size-h2: floor((@font-size-base * 2.15)); // ~30px
+@font-size-h3: ceil((@font-size-base * 1.7)); // ~24px
+@font-size-h4: ceil((@font-size-base * 1.25)); // ~18px
+@font-size-h5: @font-size-base;
+@font-size-h6: ceil((@font-size-base * 0.85)); // ~12px
+
+//** Unit-less `line-height` for use in components like buttons.
+@line-height-base: 1.428571429; // 20/14
+//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+@line-height-computed: floor((@font-size-base * @line-height-base)); // ~20px
+
+//** By default, this inherits from the `<body>`.
+@headings-font-family: inherit;
+@headings-font-weight: 500;
+@headings-line-height: 1.1;
+@headings-color: inherit;
+
+
+//-- Iconography
+//
+//## Specify custom locations of the include Glyphicons icon font. Useful for those including Bootstrap via Bower.
+
+@icon-font-path: "../fonts/";
+@icon-font-name: "glyphicons-halflings-regular";
+@icon-font-svg-id: "glyphicons_halflingsregular";
+
+//== Components
+//
+//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+
+@padding-base-vertical: 6px;
+@padding-base-horizontal: 12px;
+
+@padding-large-vertical: 10px;
+@padding-large-horizontal: 16px;
+
+@padding-small-vertical: 5px;
+@padding-small-horizontal: 10px;
+
+@padding-xs-vertical: 1px;
+@padding-xs-horizontal: 5px;
+
+@line-height-large: 1.33;
+@line-height-small: 1.5;
+
+@border-radius-base: 4px;
+@border-radius-large: 6px;
+@border-radius-small: 3px;
+
+//** Global color for active items (e.g., navs or dropdowns).
+@component-active-color: #fff;
+//** Global background color for active items (e.g., navs or dropdowns).
+@component-active-bg: @brand-primary;
+
+//** Width of the `border` for generating carets that indicator dropdowns.
+@caret-width-base: 4px;
+//** Carets increase slightly in size for larger components.
+@caret-width-large: 5px;
+
+
+//== Tables
+//
+//## Customizes the `.table` component with basic values, each used across all table variations.
+
+//** Padding for `<th>`s and `<td>`s.
+@table-cell-padding: 8px;
+//** Padding for cells in `.table-condensed`.
+@table-condensed-cell-padding: 5px;
+
+//** Default background color used for all tables.
+@table-bg: transparent;
+//** Background color used for `.table-striped`.
+@table-bg-accent: #f9f9f9;
+//** Background color used for `.table-hover`.
+@table-bg-hover: #f5f5f5;
+@table-bg-active: @table-bg-hover;
+
+//** Border color for table and cell borders.
+@table-border-color: #ddd;
+
+
+//== Buttons
+//
+//## For each of Bootstrap's buttons, define text, background and border color.
+
+@btn-font-weight: normal;
+
+@btn-default-color: #333;
+@btn-default-bg: #fff;
+@btn-default-border: #ccc;
+
+@btn-primary-color: #fff;
+@btn-primary-bg: @brand-primary;
+@btn-primary-border: darken(@btn-primary-bg, 5%);
+
+@btn-success-color: #fff;
+@btn-success-bg: @brand-success;
+@btn-success-border: darken(@btn-success-bg, 5%);
+
+@btn-info-color: #fff;
+@btn-info-bg: @brand-info;
+@btn-info-border: darken(@btn-info-bg, 5%);
+
+@btn-warning-color: #fff;
+@btn-warning-bg: @brand-warning;
+@btn-warning-border: darken(@btn-warning-bg, 5%);
+
+@btn-danger-color: #fff;
+@btn-danger-bg: @brand-danger;
+@btn-danger-border: darken(@btn-danger-bg, 5%);
+
+@btn-link-disabled-color: @gray-light;
+
+
+//== Forms
+//
+//##
+
+//** `<input>` background color
+@input-bg: #fff;
+//** `<input disabled>` background color
+@input-bg-disabled: @gray-lighter;
+
+//** Text color for `<input>`s
+@input-color: @gray;
+//** `<input>` border color
+@input-border: #ccc;
+//** `<input>` border radius
+@input-border-radius: @border-radius-base;
+//** Border color for inputs on focus
+@input-border-focus: #66afe9;
+
+//** Placeholder text color
+@input-color-placeholder: @gray-light;
+
+//** Default `.form-control` height
+@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
+//** Large `.form-control` height
+@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
+//** Small `.form-control` height
+@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
+
+@legend-color: @gray-dark;
+@legend-border-color: #e5e5e5;
+
+//** Background color for textual input addons
+@input-group-addon-bg: @gray-lighter;
+//** Border color for textual input addons
+@input-group-addon-border-color: @input-border;
+
+
+//== Dropdowns
+//
+//## Dropdown menu container and contents.
+
+//** Background for the dropdown menu.
+@dropdown-bg: #fff;
+//** Dropdown menu `border-color`.
+@dropdown-border: rgba(0,0,0,.15);
+//** Dropdown menu `border-color` **for IE8**.
+@dropdown-fallback-border: #ccc;
+//** Divider color for between dropdown items.
+@dropdown-divider-bg: #e5e5e5;
+
+//** Dropdown link text color.
+@dropdown-link-color: @gray-dark;
+//** Hover color for dropdown links.
+@dropdown-link-hover-color: darken(@gray-dark, 5%);
+//** Hover background for dropdown links.
+@dropdown-link-hover-bg: #f5f5f5;
+
+//** Active dropdown menu item text color.
+@dropdown-link-active-color: @component-active-color;
+//** Active dropdown menu item background color.
+@dropdown-link-active-bg: @component-active-bg;
+
+//** Disabled dropdown menu item background color.
+@dropdown-link-disabled-color: @gray-light;
+
+//** Text color for headers within dropdown menus.
+@dropdown-header-color: @gray-light;
+
+// Note: Deprecated @dropdown-caret-color as of v3.1.0
+@dropdown-caret-color: #000;
+
+
+//-- Z-index master list
+//
+// Warning: Avoid customizing these values. They're used for a bird's eye view
+// of components dependent on the z-axis and are designed to all work together.
+//
+// Note: These variables are not generated into the Customizer.
+
+@zindex-navbar: 1000;
+@zindex-dropdown: 1000;
+@zindex-popover: 1010;
+@zindex-tooltip: 1030;
+@zindex-navbar-fixed: 1030;
+@zindex-modal-background: 1040;
+@zindex-modal: 1050;
+
+
+//== Media queries breakpoints
+//
+//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+
+// Extra small screen / phone
+// Note: Deprecated @screen-xs and @screen-phone as of v3.0.1
+@screen-xs: 480px;
+@screen-xs-min: @screen-xs;
+@screen-phone: @screen-xs-min;
+
+// Small screen / tablet
+// Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1
+@screen-sm: 768px;
+@screen-sm-min: @screen-sm;
+@screen-tablet: @screen-sm-min;
+
+// Medium screen / desktop
+// Note: Deprecated @screen-md and @screen-desktop as of v3.0.1
+@screen-md: 992px;
+@screen-md-min: @screen-md;
+@screen-desktop: @screen-md-min;
+
+// Large screen / wide desktop
+// Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1
+@screen-lg: 1200px;
+@screen-lg-min: @screen-lg;
+@screen-lg-desktop: @screen-lg-min;
+
+// So media queries don't overlap when required, provide a maximum
+@screen-xs-max: (@screen-sm-min - 1);
+@screen-sm-max: (@screen-md-min - 1);
+@screen-md-max: (@screen-lg-min - 1);
+
+
+//== Grid system
+//
+//## Define your custom responsive grid.
+
+//** Number of columns in the grid.
+@grid-columns: 12;
+//** Padding between columns. Gets divided in half for the left and right.
+@grid-gutter-width: 30px;
+// Navbar collapse
+//** Point at which the navbar becomes uncollapsed.
+@grid-float-breakpoint: @screen-sm-min;
+//** Point at which the navbar begins collapsing.
+@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
+
+
+//== Container sizes
+//
+//## Define the maximum width of `.container` for different screen sizes.
+
+// Small screen / tablet
+@container-tablet: ((720px + @grid-gutter-width));
+//** For `@screen-sm-min` and up.
+@container-sm: @container-tablet;
+
+// Medium screen / desktop
+@container-desktop: ((940px + @grid-gutter-width));
+//** For `@screen-md-min` and up.
+@container-md: @container-desktop;
+
+// Large screen / wide desktop
+@container-large-desktop: ((1140px + @grid-gutter-width));
+//** For `@screen-lg-min` and up.
+@container-lg: @container-large-desktop;
+
+
+//== Navbar
+//
+//##
+
+// Basics of a navbar
+@navbar-height: 50px;
+@navbar-margin-bottom: @line-height-computed;
+@navbar-border-radius: @border-radius-base;
+@navbar-padding-horizontal: floor((@grid-gutter-width / 2));
+@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
+@navbar-collapse-max-height: 340px;
+
+@navbar-default-color: #777;
+@navbar-default-bg: #f8f8f8;
+@navbar-default-border: darken(@navbar-default-bg, 6.5%);
+
+// Navbar links
+@navbar-default-link-color: #777;
+@navbar-default-link-hover-color: #333;
+@navbar-default-link-hover-bg: transparent;
+@navbar-default-link-active-color: #555;
+@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%);
+@navbar-default-link-disabled-color: #ccc;
+@navbar-default-link-disabled-bg: transparent;
+
+// Navbar brand label
+@navbar-default-brand-color: @navbar-default-link-color;
+@navbar-default-brand-hover-color: darken(@navbar-default-brand-color, 10%);
+@navbar-default-brand-hover-bg: transparent;
+
+// Navbar toggle
+@navbar-default-toggle-hover-bg: #ddd;
+@navbar-default-toggle-icon-bar-bg: #888;
+@navbar-default-toggle-border-color: #ddd;
+
+
+// Inverted navbar
+// Reset inverted navbar basics
+@navbar-inverse-color: @gray-light;
+@navbar-inverse-bg: #222;
+@navbar-inverse-border: darken(@navbar-inverse-bg, 10%);
+
+// Inverted navbar links
+@navbar-inverse-link-color: @gray-light;
+@navbar-inverse-link-hover-color: #fff;
+@navbar-inverse-link-hover-bg: transparent;
+@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;
+@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%);
+@navbar-inverse-link-disabled-color: #444;
+@navbar-inverse-link-disabled-bg: transparent;
+
+// Inverted navbar brand label
+@navbar-inverse-brand-color: @navbar-inverse-link-color;
+@navbar-inverse-brand-hover-color: #fff;
+@navbar-inverse-brand-hover-bg: transparent;
+
+// Inverted navbar toggle
+@navbar-inverse-toggle-hover-bg: #333;
+@navbar-inverse-toggle-icon-bar-bg: #fff;
+@navbar-inverse-toggle-border-color: #333;
+
+
+//== Navs
+//
+//##
+
+//=== Shared nav styles
+@nav-link-padding: 10px 15px;
+@nav-link-hover-bg: @gray-lighter;
+
+@nav-disabled-link-color: @gray-light;
+@nav-disabled-link-hover-color: @gray-light;
+
+@nav-open-link-hover-color: #fff;
+
+//== Tabs
+@nav-tabs-border-color: #ddd;
+
+@nav-tabs-link-hover-border-color: @gray-lighter;
+
+@nav-tabs-active-link-hover-bg: @body-bg;
+@nav-tabs-active-link-hover-color: @gray;
+@nav-tabs-active-link-hover-border-color: #ddd;
+
+@nav-tabs-justified-link-border-color: #ddd;
+@nav-tabs-justified-active-link-border-color: @body-bg;
+
+//== Pills
+@nav-pills-border-radius: @border-radius-base;
+@nav-pills-active-link-hover-bg: @component-active-bg;
+@nav-pills-active-link-hover-color: @component-active-color;
+
+
+//== Pagination
+//
+//##
+
+@pagination-color: @link-color;
+@pagination-bg: #fff;
+@pagination-border: #ddd;
+
+@pagination-hover-color: @link-hover-color;
+@pagination-hover-bg: @gray-lighter;
+@pagination-hover-border: #ddd;
+
+@pagination-active-color: #fff;
+@pagination-active-bg: @brand-primary;
+@pagination-active-border: @brand-primary;
+
+@pagination-disabled-color: @gray-light;
+@pagination-disabled-bg: #fff;
+@pagination-disabled-border: #ddd;
+
+
+//== Pager
+//
+//##
+
+@pager-bg: @pagination-bg;
+@pager-border: @pagination-border;
+@pager-border-radius: 15px;
+
+@pager-hover-bg: @pagination-hover-bg;
+
+@pager-active-bg: @pagination-active-bg;
+@pager-active-color: @pagination-active-color;
+
+@pager-disabled-color: @pagination-disabled-color;
+
+
+//== Jumbotron
+//
+//##
+
+@jumbotron-padding: 30px;
+@jumbotron-color: inherit;
+@jumbotron-bg: @gray-lighter;
+@jumbotron-heading-color: inherit;
+@jumbotron-font-size: ceil((@font-size-base * 1.5));
+
+
+//== Form states and alerts
+//
+//## Define colors for form feedback states and, by default, alerts.
+
+@state-success-text: #3c763d;
+@state-success-bg: #dff0d8;
+@state-success-border: darken(spin(@state-success-bg, -10), 5%);
+
+@state-info-text: #31708f;
+@state-info-bg: #d9edf7;
+@state-info-border: darken(spin(@state-info-bg, -10), 7%);
+
+@state-warning-text: #8a6d3b;
+@state-warning-bg: #fcf8e3;
+@state-warning-border: darken(spin(@state-warning-bg, -10), 5%);
+
+@state-danger-text: #a94442;
+@state-danger-bg: #f2dede;
+@state-danger-border: darken(spin(@state-danger-bg, -10), 5%);
+
+
+//== Tooltips
+//
+//##
+
+//** Tooltip max width
+@tooltip-max-width: 200px;
+//** Tooltip text color
+@tooltip-color: #fff;
+//** Tooltip background color
+@tooltip-bg: #000;
+@tooltip-opacity: .9;
+
+//** Tooltip arrow width
+@tooltip-arrow-width: 5px;
+//** Tooltip arrow color
+@tooltip-arrow-color: @tooltip-bg;
+
+
+//== Popovers
+//
+//##
+
+//** Popover body background color
+@popover-bg: #fff;
+//** Popover maximum width
+@popover-max-width: 276px;
+//** Popover border color
+@popover-border-color: rgba(0,0,0,.2);
+//** Popover fallback border color
+@popover-fallback-border-color: #ccc;
+
+//** Popover title background color
+@popover-title-bg: darken(@popover-bg, 3%);
+
+//** Popover arrow width
+@popover-arrow-width: 10px;
+//** Popover arrow color
+@popover-arrow-color: #fff;
+
+//** Popover outer arrow width
+@popover-arrow-outer-width: (@popover-arrow-width + 1);
+//** Popover outer arrow color
+@popover-arrow-outer-color: fadein(@popover-border-color, 5%);
+//** Popover outer arrow fallback color
+@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%);
+
+
+//== Labels
+//
+//##
+
+//** Default label background color
+@label-default-bg: @gray-light;
+//** Primary label background color
+@label-primary-bg: @brand-primary;
+//** Success label background color
+@label-success-bg: @brand-success;
+//** Info label background color
+@label-info-bg: @brand-info;
+//** Warning label background color
+@label-warning-bg: @brand-warning;
+//** Danger label background color
+@label-danger-bg: @brand-danger;
+
+//** Default label text color
+@label-color: #fff;
+//** Default text color of a linked label
+@label-link-hover-color: #fff;
+
+
+//== Modals
+//
+//##
+
+//** Padding applied to the modal body
+@modal-inner-padding: 20px;
+
+//** Padding applied to the modal title
+@modal-title-padding: 15px;
+//** Modal title line-height
+@modal-title-line-height: @line-height-base;
+
+//** Background color of modal content area
+@modal-content-bg: #fff;
+//** Modal content border color
+@modal-content-border-color: rgba(0,0,0,.2);
+//** Modal content border color **for IE8**
+@modal-content-fallback-border-color: #999;
+
+//** Modal backdrop background color
+@modal-backdrop-bg: #000;
+//** Modal backdrop opacity
+@modal-backdrop-opacity: .5;
+//** Modal header border color
+@modal-header-border-color: #e5e5e5;
+//** Modal footer border color
+@modal-footer-border-color: @modal-header-border-color;
+
+@modal-lg: 900px;
+@modal-md: 600px;
+@modal-sm: 300px;
+
+
+//== Alerts
+//
+//## Define alert colors, border radius, and padding.
+
+@alert-padding: 15px;
+@alert-border-radius: @border-radius-base;
+@alert-link-font-weight: bold;
+
+@alert-success-bg: @state-success-bg;
+@alert-success-text: @state-success-text;
+@alert-success-border: @state-success-border;
+
+@alert-info-bg: @state-info-bg;
+@alert-info-text: @state-info-text;
+@alert-info-border: @state-info-border;
+
+@alert-warning-bg: @state-warning-bg;
+@alert-warning-text: @state-warning-text;
+@alert-warning-border: @state-warning-border;
+
+@alert-danger-bg: @state-danger-bg;
+@alert-danger-text: @state-danger-text;
+@alert-danger-border: @state-danger-border;
+
+
+//== Progress bars
+//
+//##
+
+//** Background color of the whole progress component
+@progress-bg: #f5f5f5;
+//** Progress bar text color
+@progress-bar-color: #fff;
+
+//** Default progress bar color
+@progress-bar-bg: @brand-primary;
+//** Success progress bar color
+@progress-bar-success-bg: @brand-success;
+//** Warning progress bar color
+@progress-bar-warning-bg: @brand-warning;
+//** Danger progress bar color
+@progress-bar-danger-bg: @brand-danger;
+//** Info progress bar color
+@progress-bar-info-bg: @brand-info;
+
+
+//== List group
+//
+//##
+
+//** Background color on `.list-group-item`
+@list-group-bg: #fff;
+//** `.list-group-item` border color
+@list-group-border: #ddd;
+//** List group border radius
+@list-group-border-radius: @border-radius-base;
+
+//** Background color of single list elements on hover
+@list-group-hover-bg: #f5f5f5;
+//** Text color of active list elements
+@list-group-active-color: @component-active-color;
+//** Background color of active list elements
+@list-group-active-bg: @component-active-bg;
+//** Border color of active list elements
+@list-group-active-border: @list-group-active-bg;
+@list-group-active-text-color: lighten(@list-group-active-bg, 40%);
+
+@list-group-link-color: #555;
+@list-group-link-heading-color: #333;
+
+
+//== Panels
+//
+//##
+
+@panel-bg: #fff;
+@panel-body-padding: 15px;
+@panel-border-radius: @border-radius-base;
+
+//** Border color for elements within panels
+@panel-inner-border: #ddd;
+@panel-footer-bg: #f5f5f5;
+
+@panel-default-text: @gray-dark;
+@panel-default-border: #ddd;
+@panel-default-heading-bg: #f5f5f5;
+
+@panel-primary-text: #fff;
+@panel-primary-border: @brand-primary;
+@panel-primary-heading-bg: @brand-primary;
+
+@panel-success-text: @state-success-text;
+@panel-success-border: @state-success-border;
+@panel-success-heading-bg: @state-success-bg;
+
+@panel-info-text: @state-info-text;
+@panel-info-border: @state-info-border;
+@panel-info-heading-bg: @state-info-bg;
+
+@panel-warning-text: @state-warning-text;
+@panel-warning-border: @state-warning-border;
+@panel-warning-heading-bg: @state-warning-bg;
+
+@panel-danger-text: @state-danger-text;
+@panel-danger-border: @state-danger-border;
+@panel-danger-heading-bg: @state-danger-bg;
+
+
+//== Thumbnails
+//
+//##
+
+//** Padding around the thumbnail image
+@thumbnail-padding: 4px;
+//** Thumbnail background color
+@thumbnail-bg: @body-bg;
+//** Thumbnail border color
+@thumbnail-border: #ddd;
+//** Thumbnail border radius
+@thumbnail-border-radius: @border-radius-base;
+
+//** Custom text color for thumbnail captions
+@thumbnail-caption-color: @text-color;
+//** Padding around the thumbnail caption
+@thumbnail-caption-padding: 9px;
+
+
+//== Wells
+//
+//##
+
+@well-bg: #f5f5f5;
+@well-border: darken(@well-bg, 7%);
+
+
+//== Badges
+//
+//##
+
+@badge-color: #fff;
+//** Linked badge text color on hover
+@badge-link-hover-color: #fff;
+@badge-bg: @gray-light;
+
+//** Badge text color in active nav link
+@badge-active-color: @link-color;
+//** Badge background color in active nav link
+@badge-active-bg: #fff;
+
+@badge-font-weight: bold;
+@badge-line-height: 1;
+@badge-border-radius: 10px;
+
+
+//== Breadcrumbs
+//
+//##
+
+@breadcrumb-padding-vertical: 8px;
+@breadcrumb-padding-horizontal: 15px;
+//** Breadcrumb background color
+@breadcrumb-bg: #f5f5f5;
+//** Breadcrumb text color
+@breadcrumb-color: #ccc;
+//** Text color of current page in the breadcrumb
+@breadcrumb-active-color: @gray-light;
+//** Textual separator for between breadcrumb elements
+@breadcrumb-separator: "/";
+
+
+//== Carousel
+//
+//##
+
+@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
+
+@carousel-control-color: #fff;
+@carousel-control-width: 15%;
+@carousel-control-opacity: .5;
+@carousel-control-font-size: 20px;
+
+@carousel-indicator-active-bg: #fff;
+@carousel-indicator-border-color: #fff;
+
+@carousel-caption-color: #fff;
+
+
+//== Close
+//
+//##
+
+@close-font-weight: bold;
+@close-color: #000;
+@close-text-shadow: 0 1px 0 #fff;
+
+
+//== Code
+//
+//##
+
+@code-color: #c7254e;
+@code-bg: #f9f2f4;
+
+@kbd-color: #fff;
+@kbd-bg: #333;
+
+@pre-bg: #f5f5f5;
+@pre-color: @gray-dark;
+@pre-border-color: #ccc;
+@pre-scrollable-max-height: 340px;
+
+
+//== Type
+//
+//##
+
+//** Text muted color
+@text-muted: @gray-light;
+//** Abbreviations and acronyms border color
+@abbr-border-color: @gray-light;
+//** Headings small color
+@headings-small-color: @gray-light;
+//** Blockquote small color
+@blockquote-small-color: @gray-light;
+//** Blockquote font size
+@blockquote-font-size: (@font-size-base * 1.25);
+//** Blockquote border color
+@blockquote-border-color: @gray-lighter;
+//** Page header border color
+@page-header-border-color: @gray-lighter;
+
+
+//== Miscellaneous
+//
+//##
+
+//** Horizontal line color.
+@hr-border: @gray-lighter;
+
+//** Horizontal offset for forms and lists.
+@component-offset-horizontal: 180px;
diff --git a/bower_components/bootstrap/less/wells.less b/bower_components/bootstrap/less/wells.less
new file mode 100644
index 0000000..15d072b
--- /dev/null
+++ b/bower_components/bootstrap/less/wells.less
@@ -0,0 +1,29 @@
+//
+// Wells
+// --------------------------------------------------
+
+
+// Base class
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: @well-bg;
+ border: 1px solid @well-border;
+ border-radius: @border-radius-base;
+ .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
+ blockquote {
+ border-color: #ddd;
+ border-color: rgba(0,0,0,.15);
+ }
+}
+
+// Sizes
+.well-lg {
+ padding: 24px;
+ border-radius: @border-radius-large;
+}
+.well-sm {
+ padding: 9px;
+ border-radius: @border-radius-small;
+}
diff --git a/bower_components/bootstrap/package.json b/bower_components/bootstrap/package.json
new file mode 100644
index 0000000..ed98e90
--- /dev/null
+++ b/bower_components/bootstrap/package.json
@@ -0,0 +1,70 @@
+{
+ "name": "bootstrap",
+ "description": "Sleek, intuitive, and powerful front-end framework for faster and easier web development.",
+ "version": "3.1.1",
+ "keywords": [
+ "bootstrap",
+ "css"
+ ],
+ "homepage": "http://getbootstrap.com",
+ "author": "Twitter, Inc.",
+ "scripts": {
+ "test": "grunt test"
+ },
+ "style": "./dist/css/bootstrap.css",
+ "less": "./less/bootstrap.less",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/twbs/bootstrap.git"
+ },
+ "bugs": {
+ "url": "https://github.com/twbs/bootstrap/issues"
+ },
+ "license": {
+ "type": "MIT",
+ "url": "https://github.com/twbs/bootstrap/blob/master/LICENSE"
+ },
+ "devDependencies": {
+ "btoa": "~1.1.1",
+ "canonical-json": "~0.0.3",
+ "grunt": "~0.4.2",
+ "grunt-banner": "~0.2.0",
+ "grunt-contrib-clean": "~0.5.0",
+ "grunt-contrib-concat": "~0.3.0",
+ "grunt-contrib-connect": "~0.6.0",
+ "grunt-contrib-copy": "~0.5.0",
+ "grunt-contrib-csslint": "~0.2.0",
+ "grunt-contrib-cssmin": "~0.7.0",
+ "grunt-contrib-jade": "~0.9.1",
+ "grunt-contrib-jshint": "~0.8.0",
+ "grunt-contrib-less": "~0.9.0",
+ "grunt-contrib-qunit": "~0.4.0",
+ "grunt-contrib-uglify": "~0.3.0",
+ "grunt-contrib-watch": "~0.5.3",
+ "grunt-csscomb": "~2.0.1",
+ "grunt-exec": "0.4.3",
+ "grunt-html-validation": "~0.1.13",
+ "grunt-jekyll": "~0.4.1",
+ "grunt-jscs-checker": "~0.3.0",
+ "grunt-saucelabs": "~5.0.0",
+ "grunt-sed": "~0.1.1",
+ "load-grunt-tasks": "~0.3.0",
+ "markdown": "~0.5.0"
+ },
+ "jspm": {
+ "main": "js/bootstrap",
+ "directories": {
+ "example": "examples",
+ "lib": "dist"
+ },
+ "shim": {
+ "js/bootstrap": {
+ "imports": "jquery",
+ "exports": "$"
+ }
+ },
+ "buildConfig": {
+ "uglify": true
+ }
+ }
+}
diff --git a/bower_components/bootstrap/test-infra/README.md b/bower_components/bootstrap/test-infra/README.md
new file mode 100644
index 0000000..2ee7ed9
--- /dev/null
+++ b/bower_components/bootstrap/test-infra/README.md
@@ -0,0 +1,100 @@
+## What does `s3_cache.py` do?
+
+### In general
+`s3_cache.py` maintains a cache, stored in an Amazon S3 (Simple Storage Service) bucket, of a given directory whose contents are considered non-critical and are completely & solely determined by (and should be able to be regenerated from) a single given file.
+
+The SHA-256 hash of the single file is used as the key for the cache. The directory is stored as a gzipped tarball.
+
+All the tarballs are stored in S3's Reduced Redundancy Storage (RRS) storage class, since this is cheaper and the data is non-critical.
+
+`s3_cache.py` itself never deletes cache entries; deletion should either be done manually or using automatic S3 lifecycle rules on the bucket.
+
+Similar to git, `s3_cache.py` makes the assumption that [SHA-256 will effectively never have a collision](http://stackoverflow.com/questions/4014090/is-it-safe-to-ignore-the-possibility-of-sha-collisions-in-practice).
+
+
+### For Bootstrap specifically
+`s3_cache.py` is used to cache the npm packages that our Grunt tasks depend on and the RubyGems that Jekyll depends on. (Jekyll is needed to compile our docs to HTML so that we can run them thru an HTML5 validator.)
+
+For npm, the `node_modules` directory is cached based on our `npm-shrinkwrap.canonical.json` file.
+
+For RubyGems, the `gemdir` of the current RVM-selected Ruby is cached based on the `pseudo_Gemfile.lock` file generated by our Travis build script.
+`pseudo_Gemfile.lock` contains the versions of Ruby and Jekyll that we're using (read our `.travis.yml` for details).
+
+
+## Why is `s3_cache.py` necessary?
+`s3_cache.py` is used to speed up Bootstrap's Travis builds. Installing npm packages and RubyGems used to take up a significant fraction of our total build times. Also, at the time that `s3_cache.py` was written, npm was occasionally unreliable.
+
+Travis does offer built-in caching on their paid plans, but this do-it-ourselves S3 solution is significantly cheaper since we only need caching and not Travis' other paid features.
+
+
+## Setup
+
+### Overview
+1. Create an Amazon Web Services (AWS) account.
+2. Create an Identity & Access Management (IAM) user, and note their credentials.
+3. Create an S3 bucket.
+4. Set permissions on the bucket to grant the user read+write access.
+5. Set the user credentials as secure Travis environment variables.
+
+### In detail
+1. Create an AWS account.
+2. Login to the [AWS Management Console](https://console.aws.amazon.com).
+3. Go to the IAM Management Console.
+4. Create a new user (named e.g. `travis-ci`) and generate an access key for them. Note both the Access Key ID and the Secret Access Key.
+5. Note the user's ARN (Amazon Resource Name), which can be found in the "Summary" tab of the user browser. This will be of the form: `arn:aws:iam::XXXXXXXXXXXXXX:user/the-username-goes-here`
+6. Note the user's access key, which can be found in the "Security Credentials" tab of the user browser.
+7. Go to the S3 Management Console.
+8. Create a new bucket. For a non-publicly-accessible bucket (like Bootstrap uses), it's recommended that the bucket name be random to increase security. On most *nix machines, you can easily generate a random UUID to use as the bucket name using Python:
+
+ ```bash
+ python -c "import uuid; print(uuid.uuid4())"
+ ```
+
+9. Determine and note what your bucket's ARN is. The ARN for an S3 bucket is of the form: `arn:aws:s3:::the-bucket-name-goes-here`
+10. In the bucket's Properties pane, in the "Permissions" section, click the "Edit bucket policy" button.
+11. Input and submit an IAM Policy that grants the user at least read+write rights to the bucket. AWS has a policy generator and some examples to help with crafting the policy. Here's the policy that Bootstrap uses, with the sensitive bits censored:
+
+ ```json
+ {
+ "Version": "2012-10-17",
+ "Id": "PolicyTravisReadWriteNoAdmin",
+ "Statement": [
+ {
+ "Sid": "StmtXXXXXXXXXXXXXX",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "arn:aws:iam::XXXXXXXXXXXXXX:user/travis-ci"
+ },
+ "Action": [
+ "s3:AbortMultipartUpload",
+ "s3:GetObjectVersion",
+ "s3:ListBucket",
+ "s3:DeleteObject",
+ "s3:DeleteObjectVersion",
+ "s3:GetObject",
+ "s3:PutObject"
+ ],
+ "Resource": [
+ "arn:aws:s3:::XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
+ "arn:aws:s3:::XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/*"
+ ]
+ }
+ ]
+ }
+ ```
+
+12. If you want deletion from the cache to be done automatically based on age (like Bootstrap does): In the bucket's Properties pane, in the "Lifecycle" section, add a rule to expire/delete files based on creation date.
+13. Install the [`travis` RubyGem](https://github.com/travis-ci/travis): `gem install travis`
+14. Encrypt the environment variables:
+
+ ```bash
+ travis encrypt --repo twbs/bootstrap "AWS_ACCESS_KEY_ID=XXX"
+ travis encrypt --repo twbs/bootstrap "AWS_SECRET_ACCESS_KEY=XXX"
+ travis encrypt --repo twbs/bootstrap "TWBS_S3_BUCKET=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
+ ```
+
+14. Add the resulting secure environment variables to `.travis.yml`.
+
+
+## Usage
+Read `s3_cache.py`'s source code and Bootstrap's `.travis.yml` for how to invoke and make use of `s3_cache.py`.
diff --git a/bower_components/bootstrap/test-infra/npm-shrinkwrap.canonical.json b/bower_components/bootstrap/test-infra/npm-shrinkwrap.canonical.json
new file mode 100644
index 0000000..5f4374b
--- /dev/null
+++ b/bower_components/bootstrap/test-infra/npm-shrinkwrap.canonical.json
@@ -0,0 +1 @@
+{"dependencies":{"btoa":{"from":"btoa@~1.1.1","version":"1.1.1"},"canonical-json":{"from":"canonical-json@~0.0.3","version":"0.0.4"},"grunt":{"dependencies":{"async":{"from":"async@~0.1.22","version":"0.1.22"},"coffee-script":{"from":"coffee-script@~1.3.3","version":"1.3.3"},"colors":{"from":"colors@~0.6.0","version":"0.6.2"},"dateformat":{"from":"dateformat@1.0.2-1.2.3","version":"1.0.2-1.2.3"},"eventemitter2":{"from":"eventemitter2@~0.4.13","version":"0.4.13"},"exit":{"from":"exit@~0.1.1","version":"0.1.2"},"findup-sync":{"dependencies":{"lodash":{"from":"lodash@~1.0.1","version":"1.0.1"}},"from":"findup-sync@~0.1.2","version":"0.1.2"},"getobject":{"from":"getobject@~0.1.0","version":"0.1.0"},"glob":{"dependencies":{"graceful-fs":{"from":"graceful-fs@~1.2.0","version":"1.2.3"},"inherits":{"from":"inherits@1","version":"1.0.0"}},"from":"glob@~3.1.21","version":"3.1.21"},"hooker":{"from":"hooker@~0.2.3","version":"0.2.3"},"iconv-lite":{"from":"iconv-lite@~0.2.11","version":"0.2.11"},"js-yaml":{"dependencies":{"argparse":{"dependencies":{"underscore":{"from":"underscore@1.4.x","version":"1.4.4"},"underscore.string":{"from":"underscore.string@~2.3.1","version":"2.3.3"}},"from":"argparse@~ 0.1.11","version":"0.1.15"},"esprima":{"from":"esprima@~ 1.0.2","version":"1.0.4"}},"from":"js-yaml@~2.0.5","version":"2.0.5"},"lodash":{"from":"lodash@~0.9.2","version":"0.9.2"},"minimatch":{"dependencies":{"lru-cache":{"from":"lru-cache@2","version":"2.5.0"},"sigmund":{"from":"sigmund@~1.0.0","version":"1.0.0"}},"from":"minimatch@~0.2.9","version":"0.2.14"},"nopt":{"dependencies":{"abbrev":{"from":"abbrev@1","version":"1.0.4"}},"from":"nopt@~1.0.10","version":"1.0.10"},"rimraf":{"dependencies":{"graceful-fs":{"from":"graceful-fs@~1.1","version":"1.1.14"}},"from":"rimraf@~2.0.3","version":"2.0.3"},"underscore.string":{"from":"underscore.string@~2.2.1","version":"2.2.1"},"which":{"from":"which@~1.0.5","version":"1.0.5"}},"from":"grunt@~0.4.2","version":"0.4.2"},"grunt-banner":{"from":"grunt-banner@~0.2.0","version":"0.2.0"},"grunt-contrib-clean":{"dependencies":{"rimraf":{"from":"rimraf@~2.2.1","version":"2.2.6"}},"from":"grunt-contrib-clean@~0.5.0","version":"0.5.0"},"grunt-contrib-concat":{"from":"grunt-contrib-concat@~0.3.0","version":"0.3.0"},"grunt-contrib-connect":{"dependencies":{"connect":{"dependencies":{"batch":{"from":"batch@0.5.0","version":"0.5.0"},"buffer-crc32":{"from":"buffer-crc32@0.2.1","version":"0.2.1"},"bytes":{"from":"bytes@0.2.1","version":"0.2.1"},"cookie":{"from":"cookie@0.1.0","version":"0.1.0"},"cookie-signature":{"from":"cookie-signature@1.0.1","version":"1.0.1"},"debug":{"from":"debug@>= 0.7.3 < 1","version":"0.7.4"},"fresh":{"from":"fresh@0.2.0","version":"0.2.0"},"methods":{"from":"methods@0.1.0","version":"0.1.0"},"multiparty":{"dependencies":{"readable-stream":{"dependencies":{"core-util-is":{"from":"core-util-is@~1.0.0","version":"1.0.1"},"debuglog":{"from":"debuglog@0.0.2","version":"0.0.2"}},"from":"readable-stream@~1.1.9","version":"1.1.10"},"stream-counter":{"from":"stream-counter@~0.2.0","version":"0.2.0"}},"from":"multiparty@2.2.0","version":"2.2.0"},"negotiator":{"from":"negotiator@0.3.0","version":"0.3.0"},"pause":{"from":"pause@0.0.1","version":"0.0.1"},"qs":{"from":"qs@0.6.6","version":"0.6.6"},"raw-body":{"from":"raw-body@1.1.2","version":"1.1.2"},"send":{"dependencies":{"mime":{"from":"mime@~1.2.9","version":"1.2.11"},"range-parser":{"from":"range-parser@0.0.4","version":"0.0.4"}},"from":"send@0.1.4","version":"0.1.4"},"uid2":{"from":"uid2@0.0.3","version":"0.0.3"}},"from":"connect@~2.12.0","version":"2.12.0"},"connect-livereload":{"from":"connect-livereload@~0.3.0","version":"0.3.2"},"open":{"from":"open@0.0.4","version":"0.0.4"}},"from":"grunt-contrib-connect@~0.6.0","version":"0.6.0"},"grunt-contrib-copy":{"from":"grunt-contrib-copy@~0.5.0","version":"0.5.0"},"grunt-contrib-csslint":{"dependencies":{"csslint":{"dependencies":{"parserlib":{"from":"parserlib@~0.2.2","version":"0.2.4"}},"from":"csslint@~0.10.0","version":"0.10.0"}},"from":"grunt-contrib-csslint@~0.2.0","version":"0.2.0"},"grunt-contrib-cssmin":{"dependencies":{"clean-css":{"dependencies":{"commander":{"from":"commander@2.0.x","version":"2.0.0"}},"from":"clean-css@~2.0.0","version":"2.0.8"},"grunt-lib-contrib":{"dependencies":{"zlib-browserify":{"from":"zlib-browserify@0.0.1","version":"0.0.1"}},"from":"grunt-lib-contrib@~0.6.0","version":"0.6.1"}},"from":"grunt-contrib-cssmin@~0.7.0","version":"0.7.0"},"grunt-contrib-jade":{"dependencies":{"grunt-lib-contrib":{"dependencies":{"zlib-browserify":{"from":"zlib-browserify@0.0.1","version":"0.0.1"}},"from":"grunt-lib-contrib@~0.6.1","version":"0.6.1"},"jade":{"dependencies":{"character-parser":{"from":"character-parser@1.2.0","version":"1.2.0"},"commander":{"from":"commander@2.0.0","version":"2.0.0"},"constantinople":{"dependencies":{"uglify-js":{"dependencies":{"async":{"from":"async@~0.2.6","version":"0.2.10"},"optimist":{"dependencies":{"wordwrap":{"from":"wordwrap@~0.0.2","version":"0.0.2"}},"from":"optimist@~0.3.5","version":"0.3.7"},"source-map":{"dependencies":{"amdefine":{"from":"amdefine@>=0.0.4","version":"0.1.0"}},"from":"source-map@~0.1.7","version":"0.1.31"},"uglify-to-browserify":{"from":"uglify-to-browserify@~1.0.0","version":"1.0.2"}},"from":"uglify-js@~2.4.0","version":"2.4.12"}},"from":"constantinople@~1.0.2","version":"1.0.2"},"mkdirp":{"from":"mkdirp@~0.3.5","version":"0.3.5"},"monocle":{"dependencies":{"readdirp":{"dependencies":{"minimatch":{"dependencies":{"lru-cache":{"from":"lru-cache@2","version":"2.5.0"},"sigmund":{"from":"sigmund@~1.0.0","version":"1.0.0"}},"from":"minimatch@>=0.2.4","version":"0.2.14"}},"from":"readdirp@~0.2.3","version":"0.2.5"}},"from":"monocle@1.1.50","version":"1.1.50"},"transformers":{"dependencies":{"css":{"dependencies":{"css-parse":{"from":"css-parse@1.0.4","version":"1.0.4"},"css-stringify":{"from":"css-stringify@1.0.5","version":"1.0.5"}},"from":"css@~1.0.8","version":"1.0.8"},"promise":{"dependencies":{"is-promise":{"from":"is-promise@~1","version":"1.0.0"}},"from":"promise@~2.0","version":"2.0.0"},"uglify-js":{"dependencies":{"optimist":{"dependencies":{"wordwrap":{"from":"wordwrap@~0.0.2","version":"0.0.2"}},"from":"optimist@~0.3.5","version":"0.3.7"},"source-map":{"dependencies":{"amdefine":{"from":"amdefine@>=0.0.4","version":"0.1.0"}},"from":"source-map@~0.1.7","version":"0.1.31"}},"from":"uglify-js@~2.2.5","version":"2.2.5"}},"from":"transformers@2.1.0","resolved":"https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz","version":"2.1.0"},"with":{"dependencies":{"uglify-js":{"dependencies":{"async":{"from":"async@~0.2.6","version":"0.2.10"},"optimist":{"dependencies":{"wordwrap":{"from":"wordwrap@~0.0.2","version":"0.0.2"}},"from":"optimist@~0.3.5","version":"0.3.7"},"source-map":{"dependencies":{"amdefine":{"from":"amdefine@>=0.0.4","version":"0.1.0"}},"from":"source-map@~0.1.7","version":"0.1.31"},"uglify-to-browserify":{"from":"uglify-to-browserify@~1.0.0","version":"1.0.2"}},"from":"uglify-js@2.4.0","version":"2.4.0"}},"from":"with@~2.0.0","version":"2.0.0"}},"from":"jade@~1.0.2","version":"1.0.2"},"lodash-node":{"from":"lodash-node@~2.4.1","version":"2.4.1"}},"from":"grunt-contrib-jade@~0.9.1","version":"0.9.1"},"grunt-contrib-jshint":{"dependencies":{"jshint":{"dependencies":{"cli":{"dependencies":{"glob":{"dependencies":{"inherits":{"from":"inherits@2","version":"2.0.1"}},"from":"glob@>= 3.1.4","version":"3.2.8"}},"from":"cli@0.4.x","version":"0.4.5"},"console-browserify":{"from":"console-browserify@0.1.x","version":"0.1.6"},"htmlparser2":{"dependencies":{"domelementtype":{"from":"domelementtype@1","version":"1.1.1"},"domhandler":{"from":"domhandler@2.1","version":"2.1.0"},"domutils":{"from":"domutils@1.1","version":"1.1.6"},"readable-stream":{"dependencies":{"string_decoder":{"from":"string_decoder@~0.10.x","version":"0.10.25"}},"from":"readable-stream@1.0","version":"1.0.25"}},"from":"htmlparser2@3.3.x","version":"3.3.0"},"minimatch":{"dependencies":{"lru-cache":{"from":"lru-cache@2","version":"2.5.0"},"sigmund":{"from":"sigmund@~1.0.0","version":"1.0.0"}},"from":"minimatch@0.x.x","version":"0.2.14"},"shelljs":{"from":"shelljs@0.1.x","version":"0.1.4"},"underscore":{"from":"underscore@1.4.x","version":"1.4.4"}},"from":"jshint@~2.4.0","version":"2.4.3"}},"from":"grunt-contrib-jshint@~0.8.0","version":"0.8.0"},"grunt-contrib-less":{"dependencies":{"chalk":{"dependencies":{"ansi-styles":{"from":"ansi-styles@~1.0.0","version":"1.0.0"},"has-color":{"from":"has-color@~0.1.0","version":"0.1.4"},"strip-ansi":{"from":"strip-ansi@~0.1.0","version":"0.1.1"}},"from":"chalk@~0.4.0","version":"0.4.0"},"grunt-lib-contrib":{"dependencies":{"zlib-browserify":{"from":"zlib-browserify@0.0.1","version":"0.0.1"}},"from":"grunt-lib-contrib@~0.6.1","version":"0.6.1"},"less":{"dependencies":{"clean-css":{"dependencies":{"commander":{"from":"commander@2.0.x","version":"2.0.0"}},"from":"clean-css@2.0.x","version":"2.0.8"},"mime":{"from":"mime@1.2.x","version":"1.2.11"},"mkdirp":{"from":"mkdirp@~0.3.5","version":"0.3.5"},"request":{"dependencies":{"aws-sign2":{"from":"aws-sign2@~0.5.0","version":"0.5.0"},"forever-agent":{"from":"forever-agent@~0.5.0","version":"0.5.2"},"form-data":{"dependencies":{"async":{"from":"async@~0.2.9","version":"0.2.10"},"combined-stream":{"dependencies":{"delayed-stream":{"from":"delayed-stream@0.0.5","version":"0.0.5"}},"from":"combined-stream@~0.0.4","version":"0.0.4"}},"from":"form-data@~0.1.0","version":"0.1.2"},"hawk":{"dependencies":{"boom":{"from":"boom@0.4.x","version":"0.4.2"},"cryptiles":{"from":"cryptiles@0.2.x","version":"0.2.2"},"hoek":{"from":"hoek@0.9.x","version":"0.9.1"},"sntp":{"from":"sntp@0.2.x","version":"0.2.4"}},"from":"hawk@~1.0.0","version":"1.0.0"},"http-signature":{"dependencies":{"asn1":{"from":"asn1@0.1.11","version":"0.1.11"},"assert-plus":{"from":"assert-plus@0.1.2","version":"0.1.2"},"ctype":{"from":"ctype@0.5.2","version":"0.5.2"}},"from":"http-signature@~0.10.0","version":"0.10.0"},"json-stringify-safe":{"from":"json-stringify-safe@~5.0.0","version":"5.0.0"},"node-uuid":{"from":"node-uuid@~1.4.0","version":"1.4.1"},"oauth-sign":{"from":"oauth-sign@~0.3.0","version":"0.3.0"},"qs":{"from":"qs@~0.6.0","version":"0.6.6"},"tough-cookie":{"dependencies":{"punycode":{"from":"punycode@>=0.2.0","version":"1.2.3"}},"from":"tough-cookie@>=0.12.0","version":"0.12.1"},"tunnel-agent":{"from":"tunnel-agent@~0.3.0","version":"0.3.0"}},"from":"request@>=2.12.0","version":"2.33.0"},"source-map":{"dependencies":{"amdefine":{"from":"amdefine@>=0.0.4","version":"0.1.0"}},"from":"source-map@0.1.x","version":"0.1.31"}},"from":"less@~1.6.0","version":"1.6.3"}},"from":"grunt-contrib-less@~0.9.0","version":"0.9.0"},"grunt-contrib-qunit":{"dependencies":{"grunt-lib-phantomjs":{"dependencies":{"eventemitter2":{"from":"eventemitter2@~0.4.9","version":"0.4.13"},"phantomjs":{"dependencies":{"adm-zip":{"from":"adm-zip@0.2.1","version":"0.2.1"},"kew":{"from":"kew@~0.1.7","version":"0.1.7"},"mkdirp":{"from":"mkdirp@0.3.5","version":"0.3.5"},"ncp":{"from":"ncp@0.4.2","version":"0.4.2"},"npmconf":{"dependencies":{"config-chain":{"dependencies":{"proto-list":{"from":"proto-list@~1.2.1","version":"1.2.2"}},"from":"config-chain@~1.1.1","version":"1.1.8"},"inherits":{"from":"inherits@~1.0.0","version":"1.0.0"},"ini":{"from":"ini@~1.1.0","version":"1.1.0"},"nopt":{"dependencies":{"abbrev":{"from":"abbrev@1","version":"1.0.4"}},"from":"nopt@2","version":"2.1.2"},"once":{"from":"once@~1.1.1","version":"1.1.1"},"osenv":{"from":"osenv@0.0.3","version":"0.0.3"},"semver":{"from":"semver@~1.1.0","version":"1.1.4"}},"from":"npmconf@0.0.24","version":"0.0.24"},"rimraf":{"from":"rimraf@~2.2.2","version":"2.2.6"},"which":{"from":"which@~1.0.5","version":"1.0.5"}},"from":"phantomjs@~1.9.0-1","version":"1.9.7-1"},"semver":{"from":"semver@~1.0.14","version":"1.0.14"},"temporary":{"dependencies":{"package":{"from":"package@>= 1.0.0 < 1.2.0","version":"1.0.1"}},"from":"temporary@~0.0.4","version":"0.0.8"}},"from":"grunt-lib-phantomjs@~0.5.0","version":"0.5.0"}},"from":"grunt-contrib-qunit@~0.4.0","version":"0.4.0"},"grunt-contrib-uglify":{"dependencies":{"chalk":{"dependencies":{"ansi-styles":{"from":"ansi-styles@~1.0.0","version":"1.0.0"},"has-color":{"from":"has-color@~0.1.0","version":"0.1.4"},"strip-ansi":{"from":"strip-ansi@~0.1.0","version":"0.1.1"}},"from":"chalk@~0.4.0","version":"0.4.0"},"grunt-lib-contrib":{"dependencies":{"zlib-browserify":{"from":"zlib-browserify@0.0.1","version":"0.0.1"}},"from":"grunt-lib-contrib@~0.6.1","version":"0.6.1"},"uglify-js":{"dependencies":{"async":{"from":"async@~0.2.6","version":"0.2.10"},"optimist":{"dependencies":{"wordwrap":{"from":"wordwrap@~0.0.2","version":"0.0.2"}},"from":"optimist@~0.3.5","version":"0.3.7"},"source-map":{"dependencies":{"amdefine":{"from":"amdefine@>=0.0.4","version":"0.1.0"}},"from":"source-map@~0.1.7","version":"0.1.31"},"uglify-to-browserify":{"from":"uglify-to-browserify@~1.0.0","version":"1.0.2"}},"from":"uglify-js@~2.4.0","version":"2.4.12"}},"from":"grunt-contrib-uglify@~0.3.0","version":"0.3.2"},"grunt-contrib-watch":{"dependencies":{"gaze":{"dependencies":{"globule":{"dependencies":{"glob":{"dependencies":{"graceful-fs":{"from":"graceful-fs@~1.2.0","version":"1.2.3"},"inherits":{"from":"inherits@1","version":"1.0.0"}},"from":"glob@~3.1.21","version":"3.1.21"},"lodash":{"from":"lodash@~1.0.1","version":"1.0.1"},"minimatch":{"dependencies":{"lru-cache":{"from":"lru-cache@2","version":"2.5.0"},"sigmund":{"from":"sigmund@~1.0.0","version":"1.0.0"}},"from":"minimatch@~0.2.11","version":"0.2.14"}},"from":"globule@~0.1.0","version":"0.1.0"}},"from":"gaze@~0.4.0","version":"0.4.3"},"tiny-lr":{"dependencies":{"debug":{"from":"debug@~0.7.2","version":"0.7.4"},"faye-websocket":{"from":"faye-websocket@~0.4.3","version":"0.4.4"},"noptify":{"dependencies":{"nopt":{"dependencies":{"abbrev":{"from":"abbrev@1","version":"1.0.4"}},"from":"nopt@~2.0.0","version":"2.0.0"}},"from":"noptify@latest","version":"0.0.3"},"qs":{"from":"qs@~0.5.2","version":"0.5.6"}},"from":"tiny-lr@0.0.4","version":"0.0.4"}},"from":"grunt-contrib-watch@~0.5.3","version":"0.5.3"},"grunt-csscomb":{"dependencies":{"csscomb":{"dependencies":{"commander":{"from":"commander@2.0.0","version":"2.0.0"},"gonzales-pe":{"from":"gonzales-pe@2.0.x","version":"2.0.2"},"minimatch":{"dependencies":{"lru-cache":{"from":"lru-cache@2","version":"2.5.0"},"sigmund":{"from":"sigmund@~1.0.0","version":"1.0.0"}},"from":"minimatch@0.2.12","version":"0.2.12"},"vow":{"from":"vow@0.3.11","version":"0.3.11"},"vow-fs":{"dependencies":{"node-uuid":{"from":"node-uuid@1.4.0","version":"1.4.0"},"vow-queue":{"from":"vow-queue@0.0.2","version":"0.0.2"}},"from":"vow-fs@0.2.3","version":"0.2.3"}},"from":"csscomb@~2.0.0","version":"2.0.4"}},"from":"grunt-csscomb@~2.0.1","version":"2.0.1"},"grunt-exec":{"from":"grunt-exec@0.4.3","version":"0.4.3"},"grunt-html-validation":{"dependencies":{"colors":{"from":"colors@~0.6.0","version":"0.6.2"},"request":{"dependencies":{"aws-sign":{"from":"aws-sign@~0.3.0","version":"0.3.0"},"cookie-jar":{"from":"cookie-jar@~0.3.0","version":"0.3.0"},"forever-agent":{"from":"forever-agent@~0.5.0","version":"0.5.2"},"form-data":{"dependencies":{"async":{"from":"async@~0.2.9","version":"0.2.10"},"combined-stream":{"dependencies":{"delayed-stream":{"from":"delayed-stream@0.0.5","version":"0.0.5"}},"from":"combined-stream@~0.0.4","version":"0.0.4"}},"from":"form-data@~0.1.0","version":"0.1.2"},"hawk":{"dependencies":{"boom":{"from":"boom@0.4.x","version":"0.4.2"},"cryptiles":{"from":"cryptiles@0.2.x","version":"0.2.2"},"hoek":{"from":"hoek@0.9.x","version":"0.9.1"},"sntp":{"from":"sntp@0.2.x","version":"0.2.4"}},"from":"hawk@~1.0.0","version":"1.0.0"},"http-signature":{"dependencies":{"asn1":{"from":"asn1@0.1.11","version":"0.1.11"},"assert-plus":{"from":"assert-plus@0.1.2","version":"0.1.2"},"ctype":{"from":"ctype@0.5.2","version":"0.5.2"}},"from":"http-signature@~0.10.0","version":"0.10.0"},"json-stringify-safe":{"from":"json-stringify-safe@~5.0.0","version":"5.0.0"},"mime":{"from":"mime@~1.2.9","version":"1.2.11"},"node-uuid":{"from":"node-uuid@~1.4.0","version":"1.4.1"},"oauth-sign":{"from":"oauth-sign@~0.3.0","version":"0.3.0"},"qs":{"from":"qs@~0.6.0","version":"0.6.6"},"tunnel-agent":{"from":"tunnel-agent@~0.3.0","version":"0.3.0"}},"from":"request@~2.27.0","version":"2.27.0"},"w3cjs":{"dependencies":{"commander":{"from":"commander@2.0.x","version":"2.0.0"},"superagent":{"dependencies":{"cookiejar":{"from":"cookiejar@1.3.0","version":"1.3.0"},"debug":{"from":"debug@~0.7.2","version":"0.7.4"},"emitter-component":{"from":"emitter-component@1.0.0","version":"1.0.0"},"formidable":{"from":"formidable@1.0.14","version":"1.0.14"},"methods":{"from":"methods@0.0.1","version":"0.0.1"},"mime":{"from":"mime@1.2.5","version":"1.2.5"},"qs":{"from":"qs@0.6.5","version":"0.6.5"},"reduce-component":{"from":"reduce-component@1.0.1","version":"1.0.1"}},"from":"superagent@~0.15.7","version":"0.15.7"},"superagent-proxy":{"dependencies":{"proxy-agent":{"dependencies":{"http-proxy-agent":{"dependencies":{"agent-base":{"from":"agent-base@~1.0.1","version":"1.0.1"},"debug":{"from":"debug@~0.7.2","version":"0.7.4"},"extend":{"from":"extend@~1.2.0","version":"1.2.1"}},"from":"http-proxy-agent@0","version":"0.2.4"},"https-proxy-agent":{"dependencies":{"agent-base":{"from":"agent-base@~1.0.1","version":"1.0.1"},"debug":{"from":"debug@~0.7.2","version":"0.7.4"},"extend":{"from":"extend@~1.2.0","version":"1.2.1"}},"from":"https-proxy-agent@0","version":"0.3.3"},"lru-cache":{"from":"lru-cache@~2.3.1","version":"2.3.1"},"socks-proxy-agent":{"dependencies":{"agent-base":{"from":"agent-base@~1.0.1","version":"1.0.1"},"extend":{"from":"extend@~1.2.0","version":"1.2.1"},"rainbowsocks":{"dependencies":{"debug":{"from":"debug@~0.7.2","version":"0.7.4"}},"from":"rainbowsocks@~0.1.0","version":"0.1.1"}},"from":"socks-proxy-agent@0","version":"0.1.0"}},"from":"proxy-agent@~0.0.2","version":"0.0.2"}},"from":"superagent-proxy@~0.2.0","version":"0.2.0"}},"from":"w3cjs@~0.1.22","version":"0.1.24"}},"from":"grunt-html-validation@~0.1.13","version":"0.1.13"},"grunt-jekyll":{"dependencies":{"tmp":{"from":"tmp@0.0.21","version":"0.0.21"}},"from":"grunt-jekyll@~0.4.1","version":"0.4.1"},"grunt-jscs-checker":{"dependencies":{"hooker":{"from":"hooker@0.2.3","version":"0.2.3"},"jscs":{"dependencies":{"colors":{"from":"colors@0.6.0-1","resolved":"https://registry.npmjs.org/colors/-/colors-0.6.0-1.tgz","version":"0.6.0-1"},"commander":{"dependencies":{"keypress":{"from":"keypress@0.1.x","version":"0.1.0"}},"from":"commander@1.2.0","version":"1.2.0"},"esprima":{"from":"esprima@1.0.3","version":"1.0.3"},"glob":{"dependencies":{"inherits":{"from":"inherits@2","version":"2.0.1"}},"from":"glob@3.2.7","version":"3.2.7"},"minimatch":{"dependencies":{"lru-cache":{"from":"lru-cache@2","version":"2.5.0"},"sigmund":{"from":"sigmund@~1.0.0","version":"1.0.0"}},"from":"minimatch@0.2.12","version":"0.2.12"},"vow":{"from":"vow@0.3.9","version":"0.3.9"},"vow-fs":{"dependencies":{"node-uuid":{"from":"node-uuid@1.4.0","version":"1.4.0"},"vow-queue":{"from":"vow-queue@0.0.2","version":"0.0.2"}},"from":"vow-fs@0.2.3","version":"0.2.3"},"xmlbuilder":{"dependencies":{"underscore":{"from":"underscore@>=1.5.x","version":"1.6.0"}},"from":"xmlbuilder@1.1.2","version":"1.1.2"}},"from":"jscs@~1.2.0","version":"1.2.4"},"lodash.assign":{"dependencies":{"lodash._basecreatecallback":{"dependencies":{"lodash._setbinddata":{"dependencies":{"lodash._isnative":{"from":"lodash._isnative@~2.4.1","version":"2.4.1"},"lodash.noop":{"from":"lodash.noop@~2.4.1","version":"2.4.1"}},"from":"lodash._setbinddata@~2.4.1","version":"2.4.1"},"lodash.bind":{"dependencies":{"lodash._createwrapper":{"dependencies":{"lodash._basebind":{"dependencies":{"lodash._basecreate":{"dependencies":{"lodash._isnative":{"from":"lodash._isnative@~2.4.1","version":"2.4.1"},"lodash.noop":{"from":"lodash.noop@~2.4.1","version":"2.4.1"}},"from":"lodash._basecreate@~2.4.1","version":"2.4.1"},"lodash.isobject":{"from":"lodash.isobject@~2.4.1","version":"2.4.1"}},"from":"lodash._basebind@~2.4.1","version":"2.4.1"},"lodash._basecreatewrapper":{"dependencies":{"lodash._basecreate":{"dependencies":{"lodash._isnative":{"from":"lodash._isnative@~2.4.1","version":"2.4.1"},"lodash.noop":{"from":"lodash.noop@~2.4.1","version":"2.4.1"}},"from":"lodash._basecreate@~2.4.1","version":"2.4.1"},"lodash.isobject":{"from":"lodash.isobject@~2.4.1","version":"2.4.1"}},"from":"lodash._basecreatewrapper@~2.4.1","version":"2.4.1"},"lodash.isfunction":{"from":"lodash.isfunction@~2.4.1","version":"2.4.1"}},"from":"lodash._createwrapper@~2.4.1","version":"2.4.1"},"lodash._slice":{"from":"lodash._slice@~2.4.1","version":"2.4.1"}},"from":"lodash.bind@~2.4.1","version":"2.4.1"},"lodash.identity":{"from":"lodash.identity@~2.4.1","version":"2.4.1"},"lodash.support":{"dependencies":{"lodash._isnative":{"from":"lodash._isnative@~2.4.1","version":"2.4.1"}},"from":"lodash.support@~2.4.1","version":"2.4.1"}},"from":"lodash._basecreatecallback@~2.4.1","version":"2.4.1"},"lodash._objecttypes":{"from":"lodash._objecttypes@~2.4.1","version":"2.4.1"},"lodash.keys":{"dependencies":{"lodash._isnative":{"from":"lodash._isnative@~2.4.1","version":"2.4.1"},"lodash._shimkeys":{"from":"lodash._shimkeys@~2.4.1","version":"2.4.1"},"lodash.isobject":{"from":"lodash.isobject@~2.4.1","version":"2.4.1"}},"from":"lodash.keys@~2.4.1","version":"2.4.1"}},"from":"lodash.assign@2.4.1","version":"2.4.1"},"vow":{"from":"vow@0.4.0","version":"0.4.0"}},"from":"grunt-jscs-checker@~0.3.0","version":"0.3.2"},"grunt-saucelabs":{"dependencies":{"colors":{"from":"colors@~0.6.2","version":"0.6.2"},"lodash":{"from":"lodash@~2.4.1","version":"2.4.1"},"q":{"from":"q@~1.0.0","version":"1.0.0"},"request":{"dependencies":{"aws-sign2":{"from":"aws-sign2@~0.5.0","version":"0.5.0"},"forever-agent":{"from":"forever-agent@~0.5.0","version":"0.5.2"},"form-data":{"dependencies":{"async":{"from":"async@~0.2.9","version":"0.2.10"},"combined-stream":{"dependencies":{"delayed-stream":{"from":"delayed-stream@0.0.5","version":"0.0.5"}},"from":"combined-stream@~0.0.4","version":"0.0.4"}},"from":"form-data@~0.1.0","version":"0.1.2"},"hawk":{"dependencies":{"boom":{"from":"boom@0.4.x","version":"0.4.2"},"cryptiles":{"from":"cryptiles@0.2.x","version":"0.2.2"},"hoek":{"from":"hoek@0.9.x","version":"0.9.1"},"sntp":{"from":"sntp@0.2.x","version":"0.2.4"}},"from":"hawk@~1.0.0","version":"1.0.0"},"http-signature":{"dependencies":{"asn1":{"from":"asn1@0.1.11","version":"0.1.11"},"assert-plus":{"from":"assert-plus@0.1.2","version":"0.1.2"},"ctype":{"from":"ctype@0.5.2","version":"0.5.2"}},"from":"http-signature@~0.10.0","version":"0.10.0"},"json-stringify-safe":{"from":"json-stringify-safe@~5.0.0","version":"5.0.0"},"mime":{"from":"mime@~1.2.9","version":"1.2.11"},"node-uuid":{"from":"node-uuid@~1.4.0","version":"1.4.1"},"oauth-sign":{"from":"oauth-sign@~0.3.0","version":"0.3.0"},"qs":{"from":"qs@~0.6.0","version":"0.6.6"},"tough-cookie":{"dependencies":{"punycode":{"from":"punycode@>=0.2.0","version":"1.2.3"}},"from":"tough-cookie@>=0.12.0","version":"0.12.1"},"tunnel-agent":{"from":"tunnel-agent@~0.3.0","version":"0.3.0"}},"from":"request@~2.33.0","version":"2.33.0"},"sauce-tunnel":{"dependencies":{"request":{"dependencies":{"aws-sign":{"from":"aws-sign@~0.3.0","version":"0.3.0"},"cookie-jar":{"from":"cookie-jar@~0.3.0","version":"0.3.0"},"forever-agent":{"from":"forever-agent@~0.5.0","version":"0.5.2"},"form-data":{"dependencies":{"async":{"from":"async@~0.2.7","version":"0.2.10"},"combined-stream":{"dependencies":{"delayed-stream":{"from":"delayed-stream@0.0.5","version":"0.0.5"}},"from":"combined-stream@~0.0.4","version":"0.0.4"}},"from":"form-data@0.0.8","version":"0.0.8"},"hawk":{"dependencies":{"boom":{"dependencies":{"hoek":{"from":"hoek@0.9.x","version":"0.9.1"}},"from":"boom@0.4.x","version":"0.4.2"},"cryptiles":{"from":"cryptiles@0.2.x","version":"0.2.2"},"hoek":{"from":"hoek@0.8.x","version":"0.8.5"},"sntp":{"dependencies":{"hoek":{"from":"hoek@0.9.x","version":"0.9.1"}},"from":"sntp@0.2.x","version":"0.2.4"}},"from":"hawk@~0.13.0","version":"0.13.1"},"http-signature":{"dependencies":{"asn1":{"from":"asn1@0.1.11","version":"0.1.11"},"assert-plus":{"from":"assert-plus@0.1.2","version":"0.1.2"},"ctype":{"from":"ctype@0.5.2","version":"0.5.2"}},"from":"http-signature@~0.9.11","version":"0.9.11"},"json-stringify-safe":{"from":"json-stringify-safe@~4.0.0","version":"4.0.0"},"mime":{"from":"mime@~1.2.9","version":"1.2.11"},"node-uuid":{"from":"node-uuid@~1.4.0","version":"1.4.1"},"oauth-sign":{"from":"oauth-sign@~0.3.0","version":"0.3.0"},"qs":{"from":"qs@~0.6.0","version":"0.6.6"},"tunnel-agent":{"from":"tunnel-agent@~0.3.0","version":"0.3.0"}},"from":"request@~2.21.0","version":"2.21.0"}},"from":"sauce-tunnel@~1.1.1","version":"1.1.2"},"saucelabs":{"from":"saucelabs@~0.1.1","version":"0.1.1"}},"from":"grunt-saucelabs@~5.0.0","version":"5.0.1"},"grunt-sed":{"dependencies":{"replace":{"dependencies":{"colors":{"from":"colors@0.5.x","version":"0.5.1"},"minimatch":{"dependencies":{"lru-cache":{"from":"lru-cache@2","version":"2.5.0"},"sigmund":{"from":"sigmund@~1.0.0","version":"1.0.0"}},"from":"minimatch@~0.2.9","version":"0.2.14"},"nomnom":{"dependencies":{"underscore":{"from":"underscore@~1.4.4","version":"1.4.4"}},"from":"nomnom@1.6.x","version":"1.6.2"}},"from":"replace@~0.2.4","version":"0.2.9"}},"from":"grunt-sed@~0.1.1","version":"0.1.1"},"load-grunt-tasks":{"dependencies":{"findup-sync":{"dependencies":{"glob":{"dependencies":{"graceful-fs":{"from":"graceful-fs@~1.2.0","version":"1.2.3"},"inherits":{"from":"inherits@1","version":"1.0.0"},"minimatch":{"dependencies":{"lru-cache":{"from":"lru-cache@2","version":"2.5.0"},"sigmund":{"from":"sigmund@~1.0.0","version":"1.0.0"}},"from":"minimatch@~0.2.11","version":"0.2.14"}},"from":"glob@~3.1.21","version":"3.1.21"},"lodash":{"from":"lodash@~1.0.1","version":"1.0.1"}},"from":"findup-sync@~0.1.2","version":"0.1.2"},"globule":{"dependencies":{"glob":{"dependencies":{"inherits":{"from":"inherits@2","version":"2.0.1"}},"from":"glob@~3.2.7","version":"3.2.8"},"lodash":{"from":"lodash@~2.4.1","version":"2.4.1"},"minimatch":{"dependencies":{"lru-cache":{"from":"lru-cache@2","version":"2.5.0"},"sigmund":{"from":"sigmund@~1.0.0","version":"1.0.0"}},"from":"minimatch@~0.2.9","version":"0.2.14"}},"from":"globule@~0.2.0","version":"0.2.0"}},"from":"load-grunt-tasks@~0.3.0","version":"0.3.0"},"markdown":{"dependencies":{"nopt":{"dependencies":{"abbrev":{"from":"abbrev@1","version":"1.0.4"}},"from":"nopt@~2.1.1","version":"2.1.2"}},"from":"markdown@~0.5.0","version":"0.5.0"}},"name":"bootstrap","version":"3.1.1"} \ No newline at end of file
diff --git a/bower_components/bootstrap/test-infra/requirements.txt b/bower_components/bootstrap/test-infra/requirements.txt
new file mode 100644
index 0000000..95fbf1a
--- /dev/null
+++ b/bower_components/bootstrap/test-infra/requirements.txt
@@ -0,0 +1 @@
+boto==2.20.0
diff --git a/bower_components/bootstrap/test-infra/s3_cache.py b/bower_components/bootstrap/test-infra/s3_cache.py
new file mode 100755
index 0000000..472963a
--- /dev/null
+++ b/bower_components/bootstrap/test-infra/s3_cache.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python2.7
+from __future__ import absolute_import, unicode_literals, print_function, division
+
+from sys import argv
+from os import environ, stat, remove as _delete_file
+from os.path import isfile, dirname, basename, abspath
+from hashlib import sha256
+from subprocess import check_call as run
+
+from boto.s3.connection import S3Connection
+from boto.s3.key import Key
+from boto.exception import S3ResponseError
+
+
+NEED_TO_UPLOAD_MARKER = '.need-to-upload'
+BYTES_PER_MB = 1024 * 1024
+try:
+ BUCKET_NAME = environ['TWBS_S3_BUCKET']
+except KeyError:
+ raise SystemExit("TWBS_S3_BUCKET environment variable not set!")
+
+
+def _sha256_of_file(filename):
+ hasher = sha256()
+ with open(filename, 'rb') as input_file:
+ hasher.update(input_file.read())
+ file_hash = hasher.hexdigest()
+ print('sha256({}) = {}'.format(filename, file_hash))
+ return file_hash
+
+
+def _delete_file_quietly(filename):
+ try:
+ _delete_file(filename)
+ except (OSError, IOError):
+ pass
+
+
+def _tarball_size(directory):
+ kib = stat(_tarball_filename_for(directory)).st_size // BYTES_PER_MB
+ return "{} MiB".format(kib)
+
+
+def _tarball_filename_for(directory):
+ return abspath('./{}.tar.gz'.format(basename(directory)))
+
+
+def _create_tarball(directory):
+ print("Creating tarball of {}...".format(directory))
+ run(['tar', '-czf', _tarball_filename_for(directory), '-C', dirname(directory), basename(directory)])
+
+
+def _extract_tarball(directory):
+ print("Extracting tarball of {}...".format(directory))
+ run(['tar', '-xzf', _tarball_filename_for(directory), '-C', dirname(directory)])
+
+
+def download(directory):
+ _delete_file_quietly(NEED_TO_UPLOAD_MARKER)
+ try:
+ print("Downloading {} tarball from S3...".format(friendly_name))
+ key.get_contents_to_filename(_tarball_filename_for(directory))
+ except S3ResponseError as err:
+ open(NEED_TO_UPLOAD_MARKER, 'a').close()
+ print(err)
+ raise SystemExit("Cached {} download failed!".format(friendly_name))
+ print("Downloaded {}.".format(_tarball_size(directory)))
+ _extract_tarball(directory)
+ print("{} successfully installed from cache.".format(friendly_name))
+
+
+def upload(directory):
+ _create_tarball(directory)
+ print("Uploading {} tarball to S3... ({})".format(friendly_name, _tarball_size(directory)))
+ key.set_contents_from_filename(_tarball_filename_for(directory))
+ print("{} cache successfully updated.".format(friendly_name))
+ _delete_file_quietly(NEED_TO_UPLOAD_MARKER)
+
+
+if __name__ == '__main__':
+ # Uses environment variables:
+ # AWS_ACCESS_KEY_ID -- AWS Access Key ID
+ # AWS_SECRET_ACCESS_KEY -- AWS Secret Access Key
+ argv.pop(0)
+ if len(argv) != 4:
+ raise SystemExit("USAGE: s3_cache.py <download | upload> <friendly name> <dependencies file> <directory>")
+ mode, friendly_name, dependencies_file, directory = argv
+
+ conn = S3Connection()
+ bucket = conn.lookup(BUCKET_NAME, validate=False)
+ if bucket is None:
+ raise SystemExit("Could not access bucket!")
+
+ dependencies_file_hash = _sha256_of_file(dependencies_file)
+
+ key = Key(bucket, dependencies_file_hash)
+ key.storage_class = 'REDUCED_REDUNDANCY'
+
+ if mode == 'download':
+ download(directory)
+ elif mode == 'upload':
+ if isfile(NEED_TO_UPLOAD_MARKER): # FIXME
+ upload(directory)
+ else:
+ print("No need to upload anything.")
+ else:
+ raise SystemExit("Unrecognized mode {!r}".format(mode))
diff --git a/bower_components/bootstrap/test-infra/sauce_browsers.yml b/bower_components/bootstrap/test-infra/sauce_browsers.yml
new file mode 100644
index 0000000..b9228a1
--- /dev/null
+++ b/bower_components/bootstrap/test-infra/sauce_browsers.yml
@@ -0,0 +1,83 @@
+[
+ # Docs: https://saucelabs.com/docs/platforms/webdriver
+
+ {
+ browserName: "safari",
+ platform: "OS X 10.9"
+ },
+ # {
+ # browserName: "googlechrome",
+ # platform: "OS X 10.9",
+ # version: "31"
+ # },
+ {
+ browserName: "firefox",
+ platform: "OS X 10.9"
+ },
+
+ # Mac Opera not currently supported by Sauce Labs
+
+ {
+ browserName: "internet explorer",
+ version: "11",
+ platform: "Windows 8.1"
+ },
+ {
+ browserName: "internet explorer",
+ version: "10",
+ platform: "Windows 8"
+ },
+ # {
+ # browserName: "internet explorer",
+ # version: "9",
+ # platform: "Windows 7"
+ # },
+ # {
+ # browserName: "internet explorer",
+ # version: "8",
+ # platform: "Windows 7"
+ # },
+
+ # { # Unofficial
+ # browserName: "internet explorer",
+ # version: "7",
+ # platform: "Windows XP"
+ # },
+
+ {
+ browserName: "googlechrome",
+ platform: "Windows 8.1"
+ },
+ {
+ browserName: "firefox",
+ platform: "Windows 8.1"
+ },
+
+ # Win Opera 15+ not currently supported by Sauce Labs
+
+ {
+ browserName: "iphone",
+ platform: "OS X 10.9",
+ version: "7"
+ },
+
+ # iOS Chrome not currently supported by Sauce Labs
+
+ # Linux (unofficial)
+ {
+ browserName: "googlechrome",
+ platform: "Linux"
+ },
+ {
+ browserName: "firefox",
+ platform: "Linux"
+ }
+
+ # Android Chrome not currently supported by Sauce Labs
+
+ # { # Android Browser (super-unofficial)
+ # browserName: "android",
+ # version: "4.0",
+ # platform: "Linux"
+ # }
+]
diff --git a/bower_components/bootstrap/test-infra/uncached-npm-install.sh b/bower_components/bootstrap/test-infra/uncached-npm-install.sh
new file mode 100755
index 0000000..1c56249
--- /dev/null
+++ b/bower_components/bootstrap/test-infra/uncached-npm-install.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+cp test-infra/npm-shrinkwrap.canonical.json npm-shrinkwrap.json
+npm install
+rm npm-shrinkwrap.json
diff --git a/bower_components/jquery-colorbox/.bower.json b/bower_components/jquery-colorbox/.bower.json
new file mode 100644
index 0000000..ac9f780
--- /dev/null
+++ b/bower_components/jquery-colorbox/.bower.json
@@ -0,0 +1,50 @@
+{
+ "name": "jquery-colorbox",
+ "description": "jQuery lightbox and modal window plugin",
+ "version": "1.5.9",
+ "dependencies": {
+ "jquery": ">=1.3.2"
+ },
+ "keywords": [
+ "modal",
+ "lightbox",
+ "window",
+ "popup",
+ "ui",
+ "jQuery"
+ ],
+ "authors": [
+ {
+ "name": "Jack Moore",
+ "url": "http://www.jacklmoore.com",
+ "email": "hello@jacklmoore.com"
+ }
+ ],
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "http://www.opensource.org/licenses/mit-license.php"
+ }
+ ],
+ "homepage": "http://www.jacklmoore.com/colorbox",
+ "main": "jquery.colorbox.js",
+ "ignore": [
+ "colorbox.jquery.json",
+ "colorbox.ai",
+ "content",
+ "example1/index.html",
+ "example2/index.html",
+ "example3/index.html",
+ "example4/index.html",
+ "example5/index.html"
+ ],
+ "_release": "1.5.9",
+ "_resolution": {
+ "type": "version",
+ "tag": "1.5.9",
+ "commit": "228600c97f83f7bf264e0761129e562331a458a7"
+ },
+ "_source": "git://github.com/jackmoore/colorbox.git",
+ "_target": "~1.5.8",
+ "_originalSource": "jquery-colorbox"
+} \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/README.md b/bower_components/jquery-colorbox/README.md
new file mode 100644
index 0000000..6ef95ef
--- /dev/null
+++ b/bower_components/jquery-colorbox/README.md
@@ -0,0 +1,576 @@
+## About Colorbox:
+A customizable lightbox plugin for jQuery. See the [project page](http://jacklmoore.com/colorbox/) for documentation and a demonstration, and the [FAQ](http://jacklmoore.com/colorbox/faq/) for solutions and examples to common issues. Released under the [MIT license](http://www.opensource.org/licenses/mit-license.php).
+
+## Changelog:
+
+### Version 1.5.9 - 2014/4/25
+
+* Fixed inline content bug when using child selectors. Fixes #600
+
+### Version 1.5.8 - 2014/4/15
+
+* Fixed accidental leak of global variable. References #591
+* Enabled strict mode. Fixes #597
+
+### Version 1.5.7 - 2014/4/15
+
+* Fix potential error when calling Colorbox directly. References #591
+* Potentially worked around browser limitation of reporting that an image height and width is 0 immediately after onload. Fixes #535
+
+### Version 1.5.6 - 2014/4/4
+
+* Applied maxWidth and maxHeight to the initialWidth and initialHeight. Fixes #391
+
+### Version 1.5.5 - 2014/3/13
+
+* Allow setting the overlay opacity through CSS, rather than having to use Colorbox's opacity property. Fixes #580
+
+### Version 1.5.4 - 2014/3/7
+
+* Fixed potential issue where IE9+ wouldn't close the modal when clicking on the overlay. Fixes #576
+
+### Version 1.5.3 - 2014/3/4
+
+* Added access to settings object in callbacks.
+
+### Version 1.5.2 - 2014/2/28
+
+* Added svg to image types regex.
+
+### Version 1.5.1 - 2014/2/27
+
+* Fixed regression that broke direct calls to Colorbox, ie. $.colorbox(…)
+
+### Version 1.5.0 - 2014/2/27
+
+* Changed when the className is applied: immediately on open, but only updated immediately prior to transition. Fixes #565
+* Fixed potential style flash if #cboxLoadedContent is given a background. Fixes #567
+* Misc. code cleanup
+
+### Version 1.4.37 - 2014/2/11
+
+* Fixed potential error when resizing. Fixes #254
+* Added Microsoft's JPEG XR to photo detection regex.
+
+### Version 1.4.33 - 2013/10/31
+
+* Fixed an issue where private events propagated to the document in versions of jQuery prior to 1.7. Fixes #525, Fixes #526
+
+### Version 1.4.32 - 2013/10/16
+
+* Updated stylesheets to avoid issue with using `div {max-width:100%}` (Fixes #520)
+
+### Version 1.4.31 - 2013/9/25
+
+* Used setAttribute to set londesc, so that the value is accessible via DOM Node longDesc property #508
+
+### Version 1.4.30 - 2013/9/24
+
+* Added longdesc and aria-describedby attributes to photos. Fixes #508
+
+### Version 1.4.29 - 2013/9/10
+
+* Fixed a slideshow regression from 1.4.27
+* Fixed a potential issue with the starting size of #cboxLoadedContent
+
+### Version 1.4.28 - 2013/9/4
+
+* Fixed a potential issue with using the open property with mixed slideshow and non-slideshow groups
+
+### Version 1.4.27 - 2013/7/16
+
+* Fixed a width calculation issue relating to using margin:auto on #cboxLoadedContent.
+
+### Version 1.4.26 - 2013/6/30
+
+* Fixed a regression in IE7 and IE8 that was causing an error.
+
+### Version 1.4.25 - 2013/6/28
+
+* Use an animation speed of zero between same-sized content (fixed).
+* Removed temporary fix for jQuery UI 1.8
+
+### Version 1.4.24 - 2013/6/24
+
+* Added closeButton option. Set to false to remove the close button.
+
+### Version 1.4.23 - 2013/6/23
+
+* Bugfix loading overlay/graphic append order
+
+### Version 1.4.22 - 2013/6/19
+
+* Updated manifest files for the jQuery plugin repository and Bower (no changes to plugin)
+
+### Version 1.4.21 - 2013/6/6
+
+* Replaced new Image() with document.createElement('img') to avoid a potential bug in Chrome 27.
+
+### Version 1.4.20 - 2013/6/5
+
+* Fixing bug/typo from last update.
+
+### Version 1.4.19 - 2013/6/3
+
+* Fixed bug where Colorbox was capturing ctrl+click on assigned links on windows browsers with jQuery 1.7+, rather than ignoring.
+
+### Version 1.4.18 - 2013/5/30
+
+* Fixed a scroll position issue when using $.colorbox.resize()
+
+### Version 1.4.17 - 2013/5/23
+
+* Possible fix for a Chrome 27 issue (https://github.com/jackmoore/colorbox/pull/438#issuecomment-18334804)
+
+### Version 1.4.16 - 2013/5/20
+
+* Added trapFocus setting to allow disabling of focus trapping
+
+### Version 1.4.15 - 2013/4/22
+
+* Added .webp to list of recognized image extensions
+
+### Version 1.4.14 - 2013/4/16
+
+* Added fadeOut property to control the closing fadeOut speed.
+* Removed longdesc attribute for now.
+
+### Version 1.4.13 - 2013/4/11
+
+* Fixed an error involving IE7/IE8 and legacy versions of jQuery
+
+### Version 1.4.12 - 2013/4/9
+
+* Fixed a potential conflict with Twitter Bootstrap default img styles.
+
+### Version 1.4.11 - 2013/4/9
+
+* Added `type='button'` to buttons to prevent accidental form submission
+* Added alt and longdesc attributes to photo content if they are present on the calling element.
+
+### Version 1.4.10 - 2013/4/2
+
+* Better 'old IE' feature detection that fixes an error with jQuery 2.0.0pre.
+
+### Version 1.4.9 - 2013/4/2
+
+* Fixes bug introduced in previous version.
+
+### Version 1.4.8 - 2013/4/2
+
+* Dropped IE6 support.
+* Fixed other issues with $.colorbox.remove.
+
+### Version 1.4.7 - 2013/4/1
+
+* Prevented an error if $.colorbox.remove is called during the transition.
+
+### Version 1.4.6 - 2013/3/19
+
+* Minor change to work around a jQuery 1.4.2 bug for legacy users.
+
+### Version 1.4.5 - 2013/3/10
+
+* Minor change to apply the close and className properties sooner.
+
+### Version 1.4.4 - 2013/3/10
+
+* Fixed an issue with percent-based heights in iOS
+* Fixed an issue with ajax requests being applied at the wrong time.
+
+### Version 1.4.3 - 2013/2/18
+
+* Made image preloading aware of retina settings.
+
+### Version 1.4.2 - 2013/2/18
+
+* Removed $.contains for compatibility with jQuery 1.3.x
+
+### Version 1.4.1 - 2013/2/14
+
+* Ignored left and right arrow keypresses if combined with the alt key.
+
+### Version 1.4.0 - 2013/2/12
+
+* Better accessibility:
+ * Replaced div controls with buttons
+ * Tabbed navigation confined to modal window
+ * Added aria role
+
+### Version 1.3.34 - 2013/2/4
+
+* Updated manifest for plugins.jquery.com
+
+### Version 1.3.33 - 2013/2/4
+
+* Added retina display properties: retinaImage, retinaUrl, retinaSuffix
+* Fixed iframe scrolling on iOS devices.
+
+### Version 1.3.32 - 2013/1/31
+
+* Improved internal event subscribing & fixed event bug introduced in v1.3.21
+
+### Version 1.3.31 - 2013/1/28
+
+* Fixed a size-calculation bug introduced in the previous commit.
+
+### Version 1.3.30 - 2013/1/25
+
+* Delayed border-width calculations until after opening, to avoid a bug in FF when using Colorbox in a hidden iframe.
+
+### Version 1.3.29 - 2013/1/24
+
+* Fixes bug with bubbling delegated events, introduced in the previous commit.
+
+### Version 1.3.28 - 2013/1/24
+
+* Fixed compatibility issue with old versions of jQuery (1.3.2-1.4.2)
+
+### Version 1.3.27 - 2013/1/23
+
+* Added className property.
+
+### Version 1.3.26 - 2013/1/23
+
+* Minor bugfix: clear the onload event handler after photo has loaded.
+
+### Version 1.3.25 - 2013/1/23
+
+* Removed grunt file & added Bower component.json.
+
+### Version 1.3.24 - 2013/1/22
+
+* Added generated files (jquery.colorbox.js / jquery.colorbox-min.js) back to the repository.
+
+### Version 1.3.23 - 2013/1/18
+
+* Minor bugfix for calling Colorbox on empty jQuery collections without a selector.
+
+### Version 1.3.22 - 2013/1/17
+
+* Recommit for plugins.jquery.com
+
+### Version 1.3.21 - 2013/1/15
+Files Changed: *.js
+
+* Fixed compatibility issues with jQuery 1.9
+
+### Version 1.3.20 - August 15 2012
+Files Changed:jquery.colorbox.js
+
+* Added temporary workaround for jQuery-UI 1.8 bug (http://bugs.jquery.com/ticket/12273)
+* Added *.jpe extension to the list of image types.
+
+### Version 1.3.19 - December 08 2011
+Files Changed:jquery.colorbox.js, colorbox.css (all)
+
+* Fixed bug related to using the 'fixed' property.
+* Optimized the setup procedure to be more efficient.
+* Removed $.colorbox.init() as it will no longer be needed (will self-init when called).
+* Removed use of $.browser.
+
+### Version 1.3.18 - October 07 2011
+Files Changed:jquery.colorbox.js/jquery.colorbox-min.js, colorbox.css (all) and example 1's controls.png
+
+* Fixed a regression where Flash content displayed in Colorbox would be reloaded if the browser window was resized.
+* Added safety check to make sure that Colorbox's markup is only added to the DOM a single time, even if $.colorbox.init() is called multiple times. This will allow site owners to manually initialize Colorbox if they need it before the DOM has finished loading.
+* Updated the example index.html files to be HTML5 compliant.
+* Changed the slideshow behavior so that it immediately moves to the next slide when the slideshow is started.
+* Minor regex bugfix to allow automatic detection of image URLs that include fragments.
+
+### Version 1.3.17 - May 11 2011
+Files Changed:jquery.colorbox.js/jquery.colorbox-min.js
+
+* Added properties "top", "bottom", "left" and "right" to specify a position relative to the viewport, rather than using the default centering.
+* Added property "data" to specify GET or POST data when using Ajax. Colorbox's ajax functionality is handled by jQuery's .load() method, so the data property works the same way as it does with .load().
+* Added property "fixed" which can provide fixed positioning for Colorbox, rather than absolute positioning. This will allow Colorbox to remain in a fixed position within the visitors viewport, despite scrolling. IE6 support for this was not added, it will continue to use the default absolute positioning.
+* Fixed ClearType problem with IE7.
+* Minor fixes.
+
+### Version 1.3.16 - March 01 2011
+Files Changed:jquery.colorbox.js/jquery.colorbox-min.js, colorbox.css (all) and example 4 background png files
+
+* Better IE related transparency workarounds. IE7 and up now uses the same background image sprite as other browsers.
+* Added error handling for broken image links. A message will be displayed telling the user that the image could not be loaded.
+* Added new property: 'fastIframe' and set it to true by default. Setting to fastIframe:false will delay the loading graphic removal and onComplete event until iframe has completely loaded.
+* Ability to redefine $.colorbox.close (or prev, or next) at any time.
+
+### Version 1.3.15 - October 27 2010
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Minor fixes for specific cases.
+
+### Version 1.3.14 - October 27 2010
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* In IE6, closing an iframe when using HTTPS no longer generates a security warning.
+
+### Version 1.3.13 - October 22 2010
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Changed the index.html example files to use YouTube's new embedded link format.
+* By default, Colorbox returns focus to the element it was launched from once it closes. This can now be disabled by setting the 'returnFocus' property to false. Focus was causing problems for some users who had their anchor elements inside animated containers.
+* Minor bug fix involved in using a combination of slideshow and non-slideshow content.
+
+### Version 1.3.12 - October 20 2010
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Minor bug fix involved in preloading images when using a function as a value for the href property.
+
+### Version 1.3.11 - October 19 2010
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Fixed the slideshow functionality that broke with 1.3.10
+* The slideshow now respects the loop property.
+
+### Version 1.3.10 - October 16 2010
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Fixed compatibility with jQuery 1.4.3
+* The 'open' property now accepts a function as a value, like all of the other properties.
+* Preloading now loads the correct href for images when using a dynamic (function) value for the href property.
+* Fixed bug in Safari 3 for Win where Colorbox centered on the document, rather than the visitor's viewport.
+* May have fixed an issue in Opera 10.6+ where Colorbox would rarely/randomly freeze up while switching between photos in a group.
+* Some functionality better encapsulated & minor performance improvements.
+
+### Version 1.3.9 - July 7 2010
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js/ all colorbox.css (the core styles)
+
+* Fixed a problem where iframed youtube videos would cause a security alert in IE.
+* More code is event driven now, making the source easier to grasp.
+* Removed some unnecessary style from the core CSS.
+
+### Version 1.3.8 - June 21 2010
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Fixed a bug in Chrome where it would sometimes render photos at 0 by 0 width and height (behavior introduced in recent update to Chrome).
+* Fixed a bug where the onClosed callback would fire twice (only affected 1.3.7).
+* Fixed a bug in IE7 that existed with some iframed websites that use JS to reposition the viewport caused Colorbox to move out of position.
+* Abstracted the identifiers (HTML ids & classes, and JS plugin name, method, and events) so that the plugin can be easily rebranded.
+* Small changes to improve either code readability or compression.
+
+### Version 1.3.7 - June 13 2010
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js/index.html
+
+* $.colorbox can now be used for direct calls and accessing public methods. Example: $.colorbox.close();
+* Resize now accepts 'width', 'innerWidth', 'height' and 'innerHeight'. Example: $.colorbox.resize({width:"100%"})
+* Added option (loop:false) to disable looping in a group.
+* Added options (escKey:false, arrowKey:false) to disable esc-key and arrow-key bindings.
+* Added method for removing Colorbox from a document: $.colorbox.remove();
+* Fixed a bug where iframed URLs would be truncated if they contained an unencoded apostrophe.
+* Now uses the exact href specified on an anchor, rather than the version returned by 'this.href'. This was causing "#example" to be normalized to "http://domain/#example" which interfered with how some users were setting up links to inline content.
+* Changed example documents over to HTML5.
+
+### Version 1.3.6 - Jan 13 2010
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Small change to make Colorbox compatible with jQuery 1.4
+
+### Version 1.3.5 - December 15 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Fixed a bug introduced in 1.3.4 with IE7's display of example 2 and 3, and auto-width in Opera.
+* Fixed a bug introduced in 1.3.4 where colorbox could not be launched by triggering an element's click event through JavaScript.
+* Minor refinements.
+
+### Version 1.3.4 - December 5 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Event delegation is now used for elements that Colorbox is assigned to, rather than individual click events.
+* Additional callbacks have been added to represent other stages of Colorbox's lifecycle. Available callbacks, in order of their execution: onOpen, onLoad, onComplete, onCleanup, onClosed These take place at the same time as the event hooks, but will be better suited than the hooks for targeting specific instances of Colorbox.
+* Ajax content is now immediately added to the DOM to be more compatible if that content contains script tags.
+* Focus is now returned to the calling element on closing.
+* Fixed a bug where maxHeight and maxWidth did not work for non-photo content.
+* Direct calls no longer need 'open:true', it is assumed. Example: `$.colorbox({html:'<p>Hi</p>'});`
+
+### Version 1.3.3 - November 7 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Changed $.colorbox.element() to return a jQuery object rather the DOM element.
+* jQuery.colorbox-min.js is compressed with Google's Closure Compiler rather than YUI Compressor.
+
+### Version 1.3.2 - October 27 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Added 'innerWidth' and 'innerHeight' options to allow people to easily set the size dimensions for Colorbox, without having to anticipate the size of the borders and buttons.
+* Renamed 'scrollbars' option to 'scrolling' to be in keeping with the existing HTML attribute. The option now also applies to iframes.
+* Bug fix: In Safari, positioning occassionally incorrect when using '100%' dimensions.
+* Bug fix: In IE6, the background overlay is briefly not full size when first viewing.
+* Bug fix: In Firefox, opening Colorbox causes a split second shift with a small minority of webpage layouts.
+* Simplified code in a few areas.
+
+### Version 1.3.1 - September 16 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js/colorbox.css/colorbox-ie.css(removed)
+
+* Removed the IE-only stylesheets and conditional comments for example styles 1 & 4. All CSS is handled by a single CSS file for all examples.
+* Removed user-agent sniffing from the js and replaced it with feature detection. This will allow correct rendering for visitors masking their agent type.
+
+### Version 1.3.0 - September 15 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js/colorbox.css
+
+* Added $.colorbox.resize() method to allow Colorbox to resize it's height if it's contents change.
+* Added 'scrollbars' option to allow users to turn off scrollbars when using the resize() method.
+* Renamed the 'resize' option to be less ambiguous. It's now 'scalePhotos'.
+* Renamed the 'cbox_close' event to be less ambiguous. It's now 'cbox_cleanup'. It is the first thing to happen in the close method while the 'cbox_closed' event is the last to happen.
+* Fixed a bug with the slideshow mouseover graphics that appeared after Colorbox is opened a 2nd time.
+* Fixed a bug where ClearType may not work in IE6&7 if using the fade transition.
+* Minor code optimizations to increase compression.
+
+### Version 1.2.9 - August 7 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Minor change to enable use with $.getScript();
+* Minor change to the timing of the 'cbox_load' event so that it is more useful.
+* Added a direct link to a YouTube video to the examples.
+
+### Version 1.2.8 - August 5 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Fixed a bug with the overlay in IE6
+* Fixed a bug where left & right keypress events might be prematurely unbound.
+
+### Version 1.2.7 - July 31 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js, example stylesheets and background images (core styles have not changed and the updates will not affect existing user themes / old example themes)
+
+* Code cleanup and reduction, better organization and documentation in the full source.
+* Added ability to use functions in place of static values for Colorbox's options (thanks Ken!).
+* Added an option for straight HTML. Example: `$.colorbox({html:'<p>Howdy</p>', open:true})`
+* Added an event for the beginning of the closing process. This is in addition to the event that already existed for when Colorbox had completely closed. 'cbox_close' and 'cbox_closed' respectively.
+* Fixed a minor bug in IE6 that would cause a brief content shift in the parent document when opening Colorbox.
+* Fixed a minor bug in IE6 that would reveal select elements that had a hidden visibility after closing Colorbox.
+* The 'esc' key is unbound now when Colorbox is not open, to avoid any potential conflicts.
+* Used background sprites for examples 1 & 4. Put IE-only (non-sprite) background images in a separate folder.
+* Example themes 1, 3, & 4 received slight visual tweaks.
+* Optimized pngs for smaller file size.
+* Added slices, grid, and correct sizing to the Adobe Illustrator file, all theme files are now export ready!
+
+### Version 1.2.6 - July 15 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Fixed a bug with fixed width/height images in Opera 9.64.
+* Fixed a bug with trying to set a value for rel during a direct call to Colorbox. Example: `$.colorbox({rel:'foo', open:true});`
+* Changed how href/rel/title settings are determined to avoid users having to manually update Colorbox settings if they use JavaScript to update any of those attributes, after Colorbox has been defined.
+* Fixed a FF3 bug where the back button was disabled after closing an iframe.
+
+### Version 1.2.5 - June 23 2009
+Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
+
+* Changed the point at which iframe srcs are set (to eliminate the need to refresh the iframe once it has been added to the DOM).
+* Removed unnecessary return values for a very slight code reduction.
+
+### Version 1.2.4 - June 9 2009
+Files Changed: jquery.colorbox.js, jquery.colorbox-min.js
+
+* Fixed an issue where Colorbox may not close completely if it is closed during a transition animation.
+* Minor code reduction.
+
+### Version 1.2.3 - June 4 2009
+* Fixed a png transparency stacking issue in IE.
+* More accurate Ajax auto-sizing if the user was depending on the #cboxLoadedContent ID for CSS styling.
+* Added a public function for returning the current html element that Colorbox is associated with. Example use: var that = $.colorbox.element();
+* Added bicubic scaling for resized images in the original IE7.
+* Removed the IE6 stylesheet and png files from Example 3. It now uses the same png file for the controls that the rest of the browsers use (an alpha transparency PNG8). This example now only has 2 graphics files and 1 stylesheet.
+
+### Version 1.2.2 - May 28 2009
+* Fixed an issue with the 'resize' option.
+
+### Version 1.2.1 - May 28 2009
+* Note: If you are upgrading, update your jquery.colorbox.js and colorbox.css files.
+* Added photo resizing.
+* Added a maximum width and maximum height. Example: {height:800, maxHeight:'100%'}, would allow the box to be a maximum potential height of 800px, instead of a fixed height of 800px. With maxHeight of 100% the height of Colorbox cannot exceed the height of the browser window.
+* Added 'rel' setting to add the ability to set an alternative rel for any Colorbox call. This allows the user to group any combination of elements together for a gallery, or to override an existing rel. attribute so those element are not grouped together, without having to alter their rel in the HTML.
+* Added a 'photo' setting to force Colorbox to display a link as a photo. Use this when automatic photo detection fails (such as using a url like 'photo.php' instead of 'photo.jpg', 'photo.jpg#1', or 'photo.jpg?pic=1')
+* Removed the need to ever create disposable elements to call colorbox on. Colorbox can now be called directly, without being associated with any existing element, by using the following format:
+ `$.colorbox({open:true, href:'yourLink.xxx'});`
+* Colorbox settings are now persistent and unique for each element. This allows for extremely flexible options for individual elements. You could use this to create a gallery in which each page in the gallery has different settings. One could be a photo with a fade transition, next could be an inline element with an elastic transition with a set width and height, etc.
+* For user callbacks, 'this' now refers to the element colorbox was opened from.
+* Fixed a minor grouping issue with IE6, when transition type is set to 'none'.
+* Added an Adobe Illustrator file that contains the borders and buttons used in the various examples.
+
+### Version 1.2 - May 13 2009
+* Added a slideshow feature.
+* Added re-positioning on browser resize. If the browser is resized, Colorbox will recenter itself onscreen.
+* Added hooks for key events: cbox_open, cbox_load, cbox_complete, cbox_closed.
+* Fixed an IE transparency-stacking problem, where transparent PNGs would show through to the background overlay.
+* Fixed an IE iframe issue where the ifame might shift up and to the left under certain circumstances.
+* Fixed an IE6 bug where the loading overlay was not at full height.
+* Removed the delay in switching between same-sized gallery content when using transitions.
+* Changed how iframes are loaded to make it more compatible with iframed pages that use DOM dependent JavaScript.
+* Changed how the JS is structured to be better organized and increase compression. Increased documentation.
+* Changed CSS :hover states to a .hover class. This sidesteps a minor IE8 bug with css hover states and allows easier access to hover state user styles from the JavaScript.
+* Changed: elements added to the DOM have new ID's. The naming is more consistent and less likely to cause conflicts with existing website stylesheets. All stylesheets have been updated.
+* Changed the behavior for prev/next links so that Colorbox does not get hung up on broken links. A visitor can now skip through broken or long-loading links by clicking prev/next buttons.
+* Changed the naming of variables in the parameter map to be more concise and intuitive.
+* Removed colorbox.css. Combined the colorbox.css styles with jquery.colorbox.js: the css file was not large enough to warrant being a separate file.
+
+### Version 1.1.6 - April 28 2009
+* Prevented the default action of the next & previous anchors and the left and right keys for gallery mode.
+* Fixed a bug where the title element was being added back to the DOM when closing Colorbox while using inline content.
+* Fixed a bug where IE7 would crash for example 2.
+* Smaller filesize: removed a small amount of unused code and rewrote the HTML injection with less syntax.
+* Added a public method for closing Colorbox: $.colorbox.close(). This will allow iframe users to add an event to close Colorbox without having to create an additional function.
+
+### Version 1.1.5 - April 11 2009
+* Fixed minor issues with exiting Colorbox.
+
+### Version 1.1.4 - April 08 2009
+* Fixed a bug in the fade transition where Colorbox not close completely if instructed to close during the fade-in portion of the transition.
+
+### Version 1.1.3 - April 06 2009
+* Fixed an IE6&7 issue with using Colorbox to display animated GIFs.
+
+### Version 1.1.2 - April 05 2009
+* Added ability to change content when Colorbox is already open.
+* Added vertical photo centering now works for all browsers (this feature previously excluded IE6&7).
+* Added namespacing to the esc-key keydown event for people who want to disable it: "keydown.colorClose"
+* Added 'title' setting to add the ability to set an alternative title for any Colorbox call.
+* Fixed rollover navigation issue with IE8. (Added JS-based rollover state due to a browser-bug.)
+* Fixed an overflow issue for when the fixed width/height is smaller than the size of a photo.
+* Fixed a bug in the fade transition where the border would still come up if Colorbox was closed mid-transition.
+* Switch from JSMin to Yui Compressor for minification. Minified code now under 7KB.
+
+### Version 1.1.1 - March 31 2009
+* More robust image detection regex. Now detects image file types with url fragments and/or query strings.
+* Added 'nofollow' exception to rel grouping.
+* Changed how images are loaded into the DOM to prevent premature size calculation by Colorbox.
+* Added timestamp to iframe name to prevent caching - this was a problem in some browsers if the user had multiple iframes and the visitor left the page and came back, or if they refreshed the page.
+
+### Version 1.1.0 - March 21 2009
+* Animation is now much smoother and less resource intensive.
+* Added support for % sizing.
+* Callback option added.
+* Inline content now preserves JavaScript events, and changes made while Colorbox is open are also preserved.
+* Added 'href' setting to add the ability to set an alternative href for any anchor, or to assign the Colorbox event to non-anchors.
+ Example: $('button').colorbox({'href':'process.php'})
+ Example: $('a[href='http://msn.com']).colorbox({'href':'http://google.com', iframe:true});
+* Photos are now horizontally centered if they are smaller than the lightbox size. Also vertically centered for browsers newer than IE7.
+* Buttons in the examples are now included in the 'protected zone'. The lightbox will never expand it's borders or buttons beyond an accessible area of the screen.
+* Keypress events don't queue up by holding down the arrow keys.
+* Added option to close Colorbox by clicking on the background overlay.
+* Added 'none' transition setting.
+* Changed 'contentIframe' and 'contentInline' to 'inline' and 'iframe'. Removed 'contentAjax' because it is automatically assumed for non-image file types.
+* Changed 'contentWidth' and 'contentHeight' to 'fixedWidth' and 'fixedHeight'. These sizes now reflect the total size of the lightbox, not just the inner content. This is so users can accurately anticipate % sizes without fear of creating scrollbars.
+* Clicking on a photo will now switch to the next photo in a set.
+* Loading.gif is more stable in it's position.
+* Added a minified version.
+* Code passes JSLint.
+
+### Version 1.0.5 - March 11 2009
+* Redo: Fixed a bug where IE would cut off the bottom portion of a photo, if the photo was larger than the document dimensions.
+
+### Version 1.0.4 - March 10 2009
+* Added an option to allow users to automatically open the lightbox. Example usage: $(".colorbox").colorbox({open:true});
+* Fixed a bug where IE would cut off the bottom portion of a photo, if the photo was larger than the document dimensions.
+
+### Version 1.0.3 - March 09 2009
+* Fixed vertical centering for Safari 3.0.x.
+
+### Version 1.0.2 - March 06 2009
+* Corrected a typo.
+* Changed the content-type check so that it does not assume all links to photos should actually display photos. This allows for Ajax/inline/and iframe calls on anchors linking to picture file types.
+
+### Version 1.0.1 - March 05 2009
+* Fixed keydown events (esc, left arrow, right arrow) for Webkit browsers.
+
+### Version 1.0 - March 03 2009
+* First release
diff --git a/bower_components/jquery-colorbox/bower.json b/bower_components/jquery-colorbox/bower.json
new file mode 100644
index 0000000..b4baff9
--- /dev/null
+++ b/bower_components/jquery-colorbox/bower.json
@@ -0,0 +1,41 @@
+{
+ "name": "jquery-colorbox",
+ "description": "jQuery lightbox and modal window plugin",
+ "version": "1.5.9",
+ "dependencies": {
+ "jquery": ">=1.3.2"
+ },
+ "keywords": [
+ "modal",
+ "lightbox",
+ "window",
+ "popup",
+ "ui",
+ "jQuery"
+ ],
+ "authors": [
+ {
+ "name": "Jack Moore",
+ "url": "http://www.jacklmoore.com",
+ "email": "hello@jacklmoore.com"
+ }
+ ],
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "http://www.opensource.org/licenses/mit-license.php"
+ }
+ ],
+ "homepage": "http://www.jacklmoore.com/colorbox",
+ "main": "jquery.colorbox.js",
+ "ignore": [
+ "colorbox.jquery.json",
+ "colorbox.ai",
+ "content",
+ "example1/index.html",
+ "example2/index.html",
+ "example3/index.html",
+ "example4/index.html",
+ "example5/index.html"
+ ]
+} \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/example1/colorbox.css b/bower_components/jquery-colorbox/example1/colorbox.css
new file mode 100644
index 0000000..d5613d7
--- /dev/null
+++ b/bower_components/jquery-colorbox/example1/colorbox.css
@@ -0,0 +1,70 @@
+/*
+ Colorbox Core Style:
+ The following CSS is consistent between example themes and should not be altered.
+*/
+#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
+#cboxWrapper {max-width:none;}
+#cboxOverlay{position:fixed; width:100%; height:100%;}
+#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
+#cboxContent{position:relative;}
+#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;}
+#cboxTitle{margin:0;}
+#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
+#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
+.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;}
+.cboxIframe{width:100%; height:100%; display:block; border:0; padding:0; margin:0;}
+#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;}
+
+/*
+ User Style:
+ Change the following styles to modify the appearance of Colorbox. They are
+ ordered & tabbed in a way that represents the nesting of the generated HTML.
+*/
+#cboxOverlay{background:url(images/overlay.png) repeat 0 0;}
+#colorbox{outline:0;}
+ #cboxTopLeft{width:21px; height:21px; background:url(images/controls.png) no-repeat -101px 0;}
+ #cboxTopRight{width:21px; height:21px; background:url(images/controls.png) no-repeat -130px 0;}
+ #cboxBottomLeft{width:21px; height:21px; background:url(images/controls.png) no-repeat -101px -29px;}
+ #cboxBottomRight{width:21px; height:21px; background:url(images/controls.png) no-repeat -130px -29px;}
+ #cboxMiddleLeft{width:21px; background:url(images/controls.png) left top repeat-y;}
+ #cboxMiddleRight{width:21px; background:url(images/controls.png) right top repeat-y;}
+ #cboxTopCenter{height:21px; background:url(images/border.png) 0 0 repeat-x;}
+ #cboxBottomCenter{height:21px; background:url(images/border.png) 0 -29px repeat-x;}
+ #cboxContent{background:#fff; overflow:hidden;}
+ .cboxIframe{background:#fff;}
+ #cboxError{padding:50px; border:1px solid #ccc;}
+ #cboxLoadedContent{margin-bottom:28px;}
+ #cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;}
+ #cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;}
+ #cboxLoadingOverlay{background:url(images/loading_background.png) no-repeat center center;}
+ #cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;}
+
+ /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */
+ #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; width:auto; background:none; }
+
+ /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */
+ #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;}
+
+ #cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;}
+ #cboxPrevious{position:absolute; bottom:0; left:0; background:url(images/controls.png) no-repeat -75px 0; width:25px; height:25px; text-indent:-9999px;}
+ #cboxPrevious:hover{background-position:-75px -25px;}
+ #cboxNext{position:absolute; bottom:0; left:27px; background:url(images/controls.png) no-repeat -50px 0; width:25px; height:25px; text-indent:-9999px;}
+ #cboxNext:hover{background-position:-50px -25px;}
+ #cboxClose{position:absolute; bottom:0; right:0; background:url(images/controls.png) no-repeat -25px 0; width:25px; height:25px; text-indent:-9999px;}
+ #cboxClose:hover{background-position:-25px -25px;}
+
+/*
+ The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill
+ when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to or needed in IE9.
+ See: http://jacklmoore.com/notes/ie-transparency-problems/
+*/
+.cboxIE #cboxTopLeft,
+.cboxIE #cboxTopCenter,
+.cboxIE #cboxTopRight,
+.cboxIE #cboxBottomLeft,
+.cboxIE #cboxBottomCenter,
+.cboxIE #cboxBottomRight,
+.cboxIE #cboxMiddleLeft,
+.cboxIE #cboxMiddleRight {
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF);
+} \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/css/images/border.png b/bower_components/jquery-colorbox/example1/images/border.png
index f463a10..f463a10 100644
--- a/nikola/data/themes/bootstrap/assets/css/images/border.png
+++ b/bower_components/jquery-colorbox/example1/images/border.png
Binary files differ
diff --git a/bower_components/jquery-colorbox/example1/images/controls.png b/bower_components/jquery-colorbox/example1/images/controls.png
new file mode 100644
index 0000000..dcfd6fb
--- /dev/null
+++ b/bower_components/jquery-colorbox/example1/images/controls.png
Binary files differ
diff --git a/bower_components/jquery-colorbox/example1/images/loading.gif b/bower_components/jquery-colorbox/example1/images/loading.gif
new file mode 100644
index 0000000..b4695d8
--- /dev/null
+++ b/bower_components/jquery-colorbox/example1/images/loading.gif
Binary files differ
diff --git a/nikola/data/themes/bootstrap/assets/css/images/loading_background.png b/bower_components/jquery-colorbox/example1/images/loading_background.png
index 6ae83e6..6ae83e6 100644
--- a/nikola/data/themes/bootstrap/assets/css/images/loading_background.png
+++ b/bower_components/jquery-colorbox/example1/images/loading_background.png
Binary files differ
diff --git a/nikola/data/themes/bootstrap/assets/css/images/overlay.png b/bower_components/jquery-colorbox/example1/images/overlay.png
index 53ea98f..53ea98f 100644
--- a/nikola/data/themes/bootstrap/assets/css/images/overlay.png
+++ b/bower_components/jquery-colorbox/example1/images/overlay.png
Binary files differ
diff --git a/bower_components/jquery-colorbox/example2/colorbox.css b/bower_components/jquery-colorbox/example2/colorbox.css
new file mode 100644
index 0000000..fbe8e4a
--- /dev/null
+++ b/bower_components/jquery-colorbox/example2/colorbox.css
@@ -0,0 +1,50 @@
+/*
+ Colorbox Core Style:
+ The following CSS is consistent between example themes and should not be altered.
+*/
+#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
+#cboxWrapper {max-width:none;}
+#cboxOverlay{position:fixed; width:100%; height:100%;}
+#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
+#cboxContent{position:relative;}
+#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;}
+#cboxTitle{margin:0;}
+#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
+#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
+.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;}
+.cboxIframe{width:100%; height:100%; display:block; border:0; padding:0; margin:0;}
+#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;}
+
+/*
+ User Style:
+ Change the following styles to modify the appearance of Colorbox. They are
+ ordered & tabbed in a way that represents the nesting of the generated HTML.
+*/
+#cboxOverlay{background:#fff;}
+#colorbox{outline:0;}
+ #cboxContent{margin-top:32px; overflow:visible; background:#000;}
+ .cboxIframe{background:#fff;}
+ #cboxError{padding:50px; border:1px solid #ccc;}
+ #cboxLoadedContent{background:#000; padding:1px;}
+ #cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;}
+ #cboxLoadingOverlay{background:#000;}
+ #cboxTitle{position:absolute; top:-22px; left:0; color:#000;}
+ #cboxCurrent{position:absolute; top:-22px; right:205px; text-indent:-9999px;}
+
+ /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */
+ #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; text-indent:-9999px; width:20px; height:20px; position:absolute; top:-20px; background:url(images/controls.png) no-repeat 0 0;}
+
+ /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */
+ #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;}
+
+ #cboxPrevious{background-position:0px 0px; right:44px;}
+ #cboxPrevious:hover{background-position:0px -25px;}
+ #cboxNext{background-position:-25px 0px; right:22px;}
+ #cboxNext:hover{background-position:-25px -25px;}
+ #cboxClose{background-position:-50px 0px; right:0;}
+ #cboxClose:hover{background-position:-50px -25px;}
+ .cboxSlideshow_on #cboxPrevious, .cboxSlideshow_off #cboxPrevious{right:66px;}
+ .cboxSlideshow_on #cboxSlideshow{background-position:-75px -25px; right:44px;}
+ .cboxSlideshow_on #cboxSlideshow:hover{background-position:-100px -25px;}
+ .cboxSlideshow_off #cboxSlideshow{background-position:-100px 0px; right:44px;}
+ .cboxSlideshow_off #cboxSlideshow:hover{background-position:-75px -25px;}
diff --git a/bower_components/jquery-colorbox/example2/images/controls.png b/bower_components/jquery-colorbox/example2/images/controls.png
new file mode 100644
index 0000000..8569b57
--- /dev/null
+++ b/bower_components/jquery-colorbox/example2/images/controls.png
Binary files differ
diff --git a/bower_components/jquery-colorbox/example2/images/loading.gif b/bower_components/jquery-colorbox/example2/images/loading.gif
new file mode 100644
index 0000000..19c67bb
--- /dev/null
+++ b/bower_components/jquery-colorbox/example2/images/loading.gif
Binary files differ
diff --git a/bower_components/jquery-colorbox/example3/colorbox.css b/bower_components/jquery-colorbox/example3/colorbox.css
new file mode 100644
index 0000000..6b1b6d4
--- /dev/null
+++ b/bower_components/jquery-colorbox/example3/colorbox.css
@@ -0,0 +1,45 @@
+/*
+ Colorbox Core Style:
+ The following CSS is consistent between example themes and should not be altered.
+*/
+#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
+#cboxWrapper {max-width:none;}
+#cboxOverlay{position:fixed; width:100%; height:100%;}
+#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
+#cboxContent{position:relative;}
+#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;}
+#cboxTitle{margin:0;}
+#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
+#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
+.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;}
+.cboxIframe{width:100%; height:100%; display:block; border:0; padding:0; margin:0;}
+#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;}
+
+/*
+ User Style:
+ Change the following styles to modify the appearance of Colorbox. They are
+ ordered & tabbed in a way that represents the nesting of the generated HTML.
+*/
+#cboxOverlay{background:#000;}
+#colorbox{outline:0;}
+ #cboxContent{margin-top:20px;background:#000;}
+ .cboxIframe{background:#fff;}
+ #cboxError{padding:50px; border:1px solid #ccc;}
+ #cboxLoadedContent{border:5px solid #000; background:#fff;}
+ #cboxTitle{position:absolute; top:-20px; left:0; color:#ccc;}
+ #cboxCurrent{position:absolute; top:-20px; right:0px; color:#ccc;}
+ #cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;}
+
+ /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */
+ #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; width:auto; background:none; }
+
+ /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */
+ #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;}
+
+ #cboxSlideshow{position:absolute; top:-20px; right:90px; color:#fff;}
+ #cboxPrevious{position:absolute; top:50%; left:5px; margin-top:-32px; background:url(images/controls.png) no-repeat top left; width:28px; height:65px; text-indent:-9999px;}
+ #cboxPrevious:hover{background-position:bottom left;}
+ #cboxNext{position:absolute; top:50%; right:5px; margin-top:-32px; background:url(images/controls.png) no-repeat top right; width:28px; height:65px; text-indent:-9999px;}
+ #cboxNext:hover{background-position:bottom right;}
+ #cboxClose{position:absolute; top:5px; right:5px; display:block; background:url(images/controls.png) no-repeat top center; width:38px; height:19px; text-indent:-9999px;}
+ #cboxClose:hover{background-position:bottom center;}
diff --git a/bower_components/jquery-colorbox/example3/images/controls.png b/bower_components/jquery-colorbox/example3/images/controls.png
new file mode 100644
index 0000000..e1e9798
--- /dev/null
+++ b/bower_components/jquery-colorbox/example3/images/controls.png
Binary files differ
diff --git a/bower_components/jquery-colorbox/example3/images/loading.gif b/bower_components/jquery-colorbox/example3/images/loading.gif
new file mode 100644
index 0000000..19c67bb
--- /dev/null
+++ b/bower_components/jquery-colorbox/example3/images/loading.gif
Binary files differ
diff --git a/bower_components/jquery-colorbox/example4/colorbox.css b/bower_components/jquery-colorbox/example4/colorbox.css
new file mode 100644
index 0000000..152ca82
--- /dev/null
+++ b/bower_components/jquery-colorbox/example4/colorbox.css
@@ -0,0 +1,66 @@
+/*
+ Colorbox Core Style:
+ The following CSS is consistent between example themes and should not be altered.
+*/
+#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
+#cboxWrapper {max-width:none;}
+#cboxOverlay{position:fixed; width:100%; height:100%;}
+#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
+#cboxContent{position:relative;}
+#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;}
+#cboxTitle{margin:0;}
+#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
+#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
+.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;}
+.cboxIframe{width:100%; height:100%; display:block; border:0; padding:0; margin:0;}
+#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;}
+
+/*
+ User Style:
+ Change the following styles to modify the appearance of Colorbox. They are
+ ordered & tabbed in a way that represents the nesting of the generated HTML.
+*/
+#cboxOverlay{background:#fff;}
+#colorbox{outline:0;}
+ #cboxTopLeft{width:25px; height:25px; background:url(images/border1.png) no-repeat 0 0;}
+ #cboxTopCenter{height:25px; background:url(images/border1.png) repeat-x 0 -50px;}
+ #cboxTopRight{width:25px; height:25px; background:url(images/border1.png) no-repeat -25px 0;}
+ #cboxBottomLeft{width:25px; height:25px; background:url(images/border1.png) no-repeat 0 -25px;}
+ #cboxBottomCenter{height:25px; background:url(images/border1.png) repeat-x 0 -75px;}
+ #cboxBottomRight{width:25px; height:25px; background:url(images/border1.png) no-repeat -25px -25px;}
+ #cboxMiddleLeft{width:25px; background:url(images/border2.png) repeat-y 0 0;}
+ #cboxMiddleRight{width:25px; background:url(images/border2.png) repeat-y -25px 0;}
+ #cboxContent{background:#fff; overflow:hidden;}
+ .cboxIframe{background:#fff;}
+ #cboxError{padding:50px; border:1px solid #ccc;}
+ #cboxLoadedContent{margin-bottom:20px;}
+ #cboxTitle{position:absolute; bottom:0px; left:0; text-align:center; width:100%; color:#999;}
+ #cboxCurrent{position:absolute; bottom:0px; left:100px; color:#999;}
+ #cboxLoadingOverlay{background:#fff url(images/loading.gif) no-repeat 5px 5px;}
+
+ /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */
+ #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; width:auto; background:none; }
+
+ /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */
+ #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;}
+
+ #cboxSlideshow{position:absolute; bottom:0px; right:42px; color:#444;}
+ #cboxPrevious{position:absolute; bottom:0px; left:0; color:#444;}
+ #cboxNext{position:absolute; bottom:0px; left:63px; color:#444;}
+ #cboxClose{position:absolute; bottom:0; right:0; display:block; color:#444;}
+
+/*
+ The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill
+ when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to or needed in IE9.
+ See: http://jacklmoore.com/notes/ie-transparency-problems/
+*/
+.cboxIE #cboxTopLeft,
+.cboxIE #cboxTopCenter,
+.cboxIE #cboxTopRight,
+.cboxIE #cboxBottomLeft,
+.cboxIE #cboxBottomCenter,
+.cboxIE #cboxBottomRight,
+.cboxIE #cboxMiddleLeft,
+.cboxIE #cboxMiddleRight {
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF);
+} \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/example4/images/border1.png b/bower_components/jquery-colorbox/example4/images/border1.png
new file mode 100644
index 0000000..0ddc704
--- /dev/null
+++ b/bower_components/jquery-colorbox/example4/images/border1.png
Binary files differ
diff --git a/bower_components/jquery-colorbox/example4/images/border2.png b/bower_components/jquery-colorbox/example4/images/border2.png
new file mode 100644
index 0000000..aa62a0b
--- /dev/null
+++ b/bower_components/jquery-colorbox/example4/images/border2.png
Binary files differ
diff --git a/bower_components/jquery-colorbox/example4/images/loading.gif b/bower_components/jquery-colorbox/example4/images/loading.gif
new file mode 100644
index 0000000..602ce3c
--- /dev/null
+++ b/bower_components/jquery-colorbox/example4/images/loading.gif
Binary files differ
diff --git a/bower_components/jquery-colorbox/example5/colorbox.css b/bower_components/jquery-colorbox/example5/colorbox.css
new file mode 100644
index 0000000..54f9ba7
--- /dev/null
+++ b/bower_components/jquery-colorbox/example5/colorbox.css
@@ -0,0 +1,58 @@
+/*
+ Colorbox Core Style:
+ The following CSS is consistent between example themes and should not be altered.
+*/
+#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
+#cboxWrapper {max-width:none;}
+#cboxOverlay{position:fixed; width:100%; height:100%;}
+#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
+#cboxContent{position:relative;}
+#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;}
+#cboxTitle{margin:0;}
+#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
+#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
+.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;}
+.cboxIframe{width:100%; height:100%; display:block; border:0; padding:0; margin:0;}
+#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;}
+
+/*
+ User Style:
+ Change the following styles to modify the appearance of Colorbox. They are
+ ordered & tabbed in a way that represents the nesting of the generated HTML.
+*/
+#cboxOverlay{background:#000;}
+#colorbox{outline:0;}
+ #cboxTopLeft{width:14px; height:14px; background:url(images/controls.png) no-repeat 0 0;}
+ #cboxTopCenter{height:14px; background:url(images/border.png) repeat-x top left;}
+ #cboxTopRight{width:14px; height:14px; background:url(images/controls.png) no-repeat -36px 0;}
+ #cboxBottomLeft{width:14px; height:43px; background:url(images/controls.png) no-repeat 0 -32px;}
+ #cboxBottomCenter{height:43px; background:url(images/border.png) repeat-x bottom left;}
+ #cboxBottomRight{width:14px; height:43px; background:url(images/controls.png) no-repeat -36px -32px;}
+ #cboxMiddleLeft{width:14px; background:url(images/controls.png) repeat-y -175px 0;}
+ #cboxMiddleRight{width:14px; background:url(images/controls.png) repeat-y -211px 0;}
+ #cboxContent{background:#fff; overflow:visible;}
+ .cboxIframe{background:#fff;}
+ #cboxError{padding:50px; border:1px solid #ccc;}
+ #cboxLoadedContent{margin-bottom:5px;}
+ #cboxLoadingOverlay{background:url(images/loading_background.png) no-repeat center center;}
+ #cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;}
+ #cboxTitle{position:absolute; bottom:-25px; left:0; text-align:center; width:100%; font-weight:bold; color:#7C7C7C;}
+ #cboxCurrent{position:absolute; bottom:-25px; left:58px; font-weight:bold; color:#7C7C7C;}
+
+ /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */
+ #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; position:absolute; bottom:-29px; background:url(images/controls.png) no-repeat 0px 0px; width:23px; height:23px; text-indent:-9999px;}
+
+ /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */
+ #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;}
+
+ #cboxPrevious{left:0px; background-position: -51px -25px;}
+ #cboxPrevious:hover{background-position:-51px 0px;}
+ #cboxNext{left:27px; background-position:-75px -25px;}
+ #cboxNext:hover{background-position:-75px 0px;}
+ #cboxClose{right:0; background-position:-100px -25px;}
+ #cboxClose:hover{background-position:-100px 0px;}
+
+ .cboxSlideshow_on #cboxSlideshow{background-position:-125px 0px; right:27px;}
+ .cboxSlideshow_on #cboxSlideshow:hover{background-position:-150px 0px;}
+ .cboxSlideshow_off #cboxSlideshow{background-position:-150px -25px; right:27px;}
+ .cboxSlideshow_off #cboxSlideshow:hover{background-position:-125px 0px;} \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/example5/images/border.png b/bower_components/jquery-colorbox/example5/images/border.png
new file mode 100644
index 0000000..df13bb6
--- /dev/null
+++ b/bower_components/jquery-colorbox/example5/images/border.png
Binary files differ
diff --git a/bower_components/jquery-colorbox/example5/images/controls.png b/bower_components/jquery-colorbox/example5/images/controls.png
new file mode 100644
index 0000000..65cfd1d
--- /dev/null
+++ b/bower_components/jquery-colorbox/example5/images/controls.png
Binary files differ
diff --git a/bower_components/jquery-colorbox/example5/images/loading.gif b/bower_components/jquery-colorbox/example5/images/loading.gif
new file mode 100644
index 0000000..b4695d8
--- /dev/null
+++ b/bower_components/jquery-colorbox/example5/images/loading.gif
Binary files differ
diff --git a/bower_components/jquery-colorbox/example5/images/loading_background.png b/bower_components/jquery-colorbox/example5/images/loading_background.png
new file mode 100644
index 0000000..9de11f4
--- /dev/null
+++ b/bower_components/jquery-colorbox/example5/images/loading_background.png
Binary files differ
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-ar.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-ar.js
new file mode 100644
index 0000000..6c4228c
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-ar.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Arabic (ar)
+ translated by: A.Rhman Sayes
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "الصورة {current} من {total}",
+ previous: "السابق",
+ next: "التالي",
+ close: "إغلاق",
+ xhrError: "حدث خطأ أثناء تحميل المحتوى.",
+ imgError: "حدث خطأ أثناء تحميل الصورة.",
+ slideshowStart: "تشغيل العرض",
+ slideshowStop: "إيقاف العرض"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-bg.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-bg.js
new file mode 100644
index 0000000..de7e4a1
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-bg.js
@@ -0,0 +1,16 @@
+/*
+ jQuery Colorbox language configuration
+ language: Bulgarian (bg)
+ translated by: Marian M.Bida
+ site: webmax.bg
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "изображение {current} от {total}",
+ previous: "предишна",
+ next: "следваща",
+ close: "затвори",
+ xhrError: "Неуспешно зареждане на съдържанието.",
+ imgError: "Неуспешно зареждане на изображението.",
+ slideshowStart: "пусни слайд-шоу",
+ slideshowStop: "спри слайд-шоу"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-ca.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-ca.js
new file mode 100644
index 0000000..173c05f
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-ca.js
@@ -0,0 +1,13 @@
+/*
+ jQuery Colorbox language configuration
+ language: Catala (ca)
+ translated by: eduard salla
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Imatge {current} de {total}",
+ previous: "Anterior",
+ next: "Següent",
+ close: "Tancar",
+ xhrError: "Error en la càrrega del contingut.",
+ imgError: "Error en la càrrega de la imatge."
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-cs.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-cs.js
new file mode 100644
index 0000000..9649fd4
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-cs.js
@@ -0,0 +1,16 @@
+/*
+ jQuery Colorbox language configuration
+ language: Czech (cs)
+ translated by: Filip Novak
+ site: mame.napilno.cz/filip-novak
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "{current}. obrázek z {total}",
+ previous: "Předchozí",
+ next: "Následující",
+ close: "Zavřít",
+ xhrError: "Obsah se nepodařilo načíst.",
+ imgError: "Obrázek se nepodařilo načíst.",
+ slideshowStart: "Spustit slideshow",
+ slideshowStop: "Zastavit slideshow"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-da.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-da.js
new file mode 100644
index 0000000..676fffe
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-da.js
@@ -0,0 +1,16 @@
+/*
+ jQuery Colorbox language configuration
+ language: Danish (da)
+ translated by: danieljuhl
+ site: danieljuhl.dk
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Billede {current} af {total}",
+ previous: "Forrige",
+ next: "Næste",
+ close: "Luk",
+ xhrError: "Indholdet fejlede i indlæsningen.",
+ imgError: "Billedet fejlede i indlæsningen.",
+ slideshowStart: "Start slideshow",
+ slideshowStop: "Stop slideshow"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-de.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-de.js
new file mode 100644
index 0000000..d489379
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-de.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: German (de)
+ translated by: wallenium
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Bild {current} von {total}",
+ previous: "Zurück",
+ next: "Vor",
+ close: "Schließen",
+ xhrError: "Dieser Inhalt konnte nicht geladen werden.",
+ imgError: "Dieses Bild konnte nicht geladen werden.",
+ slideshowStart: "Slideshow starten",
+ slideshowStop: "Slideshow anhalten"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-es.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-es.js
new file mode 100644
index 0000000..11296fc
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-es.js
@@ -0,0 +1,13 @@
+/*
+ jQuery Colorbox language configuration
+ language: Spanish (es)
+ translated by: migolo
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Imagen {current} de {total}",
+ previous: "Anterior",
+ next: "Siguiente",
+ close: "Cerrar",
+ xhrError: "Error en la carga del contenido.",
+ imgError: "Error en la carga de la imagen."
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-et.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-et.js
new file mode 100644
index 0000000..60a4e88
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-et.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Estonian (et)
+ translated by: keevitaja
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "{current}/{total}",
+ previous: "eelmine",
+ next: "järgmine",
+ close: "sulge",
+ xhrError: "Sisu ei õnnestunud laadida.",
+ imgError: "Pilti ei õnnestunud laadida.",
+ slideshowStart: "Käivita slaidid",
+ slideshowStop: "Peata slaidid"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-fa.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-fa.js
new file mode 100644
index 0000000..32869a4
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-fa.js
@@ -0,0 +1,18 @@
+/*
+ jQuery Colorbox language configuration
+ language: Persian (Farsi)
+ translated by: Mahdi Jaberzadeh Ansari (MJZSoft)
+ site: www.mjzsoft.ir
+ email: mahdijaberzadehansari (at) yahoo.co.uk
+ Please note : Persian language is right to left like arabic.
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "تصویر {current} از {total}",
+ previous: "قبلی",
+ next: "بعدی",
+ close: "بستن",
+ xhrError: "متاسفانه محتویات مورد نظر قابل نمایش نیست.",
+ imgError: "متاسفانه بارگذاری این عکس با مشکل مواجه شده است.",
+ slideshowStart: "آغاز نمایش خودکار",
+ slideshowStop: "توقف نمایش خودکار"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-fi.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-fi.js
new file mode 100644
index 0000000..ac03fe0
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-fi.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Finnish (fi)
+ translated by: Mikko
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Kuva {current} / {total}",
+ previous: "Edellinen",
+ next: "Seuraava",
+ close: "Sulje",
+ xhrError: "Sisällön lataaminen epäonnistui.",
+ imgError: "Kuvan lataaminen epäonnistui.",
+ slideshowStart: "Aloita kuvaesitys.",
+ slideshowStop: "Lopeta kuvaesitys."
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-fr.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-fr.js
new file mode 100644
index 0000000..f76352b
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-fr.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: French (fr)
+ translated by: oaubert
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "image {current} sur {total}",
+ previous: "pr&eacute;c&eacute;dente",
+ next: "suivante",
+ close: "fermer",
+ xhrError: "Impossible de charger ce contenu.",
+ imgError: "Impossible de charger cette image.",
+ slideshowStart: "d&eacute;marrer la pr&eacute;sentation",
+ slideshowStop: "arr&ecirc;ter la pr&eacute;sentation"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-gl.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-gl.js
new file mode 100644
index 0000000..3641b51
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-gl.js
@@ -0,0 +1,13 @@
+/*
+ jQuery Colorbox language configuration
+ language: Galician (gl)
+ translated by: donatorouco
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Imaxe {current} de {total}",
+ previous: "Anterior",
+ next: "Seguinte",
+ close: "Pechar",
+ xhrError: "Erro na carga do contido.",
+ imgError: "Erro na carga da imaxe."
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-gr.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-gr.js
new file mode 100644
index 0000000..0d2c1bb
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-gr.js
@@ -0,0 +1,16 @@
+/*
+ jQuery Colorbox language configuration
+ language: Greek (gr)
+ translated by: S.Demirtzoglou
+ site: webiq.gr
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Εικόνα {current} από {total}",
+ previous: "Προηγούμενη",
+ next: "Επόμενη",
+ close: "Απόκρυψη",
+ xhrError: "Το περιεχόμενο δεν μπόρεσε να φορτωθεί.",
+ imgError: "Απέτυχε η φόρτωση της εικόνας.",
+ slideshowStart: "Έναρξη παρουσίασης",
+ slideshowStop: "Παύση παρουσίασης"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-he.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-he.js
new file mode 100644
index 0000000..78908e3
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-he.js
@@ -0,0 +1,16 @@
+/*
+ jQuery Colorbox language configuration
+ language: Hebrew (he)
+ translated by: DavidCo
+ site: DavidCo.me
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "תמונה {current} מתוך {total}",
+ previous: "הקודם",
+ next: "הבא",
+ close: "סגור",
+ xhrError: "שגיאה בטעינת התוכן.",
+ imgError: "שגיאה בטעינת התמונה.",
+ slideshowStart: "התחל מצגת",
+ slideshowStop: "עצור מצגת"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-hr.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-hr.js
new file mode 100644
index 0000000..7eb62be
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-hr.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Croatian (hr)
+ translated by: Mladen Bicanic (base.hr)
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Slika {current} od {total}",
+ previous: "Prethodna",
+ next: "Sljedeća",
+ close: "Zatvori",
+ xhrError: "Neuspješno učitavanje sadržaja.",
+ imgError: "Neuspješno učitavanje slike.",
+ slideshowStart: "Pokreni slideshow",
+ slideshowStop: "Zaustavi slideshow"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-hu.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-hu.js
new file mode 100644
index 0000000..72e9d36
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-hu.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Hungarian (hu)
+ translated by: kovadani
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "{current}/{total} kép",
+ previous: "Előző",
+ next: "Következő",
+ close: "Bezár",
+ xhrError: "A tartalmat nem sikerült betölteni.",
+ imgError: "A képet nem sikerült betölteni.",
+ slideshowStart: "Diavetítés indítása",
+ slideshowStop: "Diavetítés leállítása"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-id.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-id.js
new file mode 100644
index 0000000..81a62df
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-id.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Indonesian (id)
+ translated by: sarwasunda
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "ke {current} dari {total}",
+ previous: "Sebelumnya",
+ next: "Berikutnya",
+ close: "Tutup",
+ xhrError: "Konten ini tidak dapat dimuat.",
+ imgError: "Gambar ini tidak dapat dimuat.",
+ slideshowStart: "Putar",
+ slideshowStop: "Berhenti"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-it.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-it.js
new file mode 100644
index 0000000..2a4af64
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-it.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Italian (it)
+ translated by: maur8ino
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Immagine {current} di {total}",
+ previous: "Precedente",
+ next: "Successiva",
+ close: "Chiudi",
+ xhrError: "Errore nel caricamento del contenuto.",
+ imgError: "Errore nel caricamento dell'immagine.",
+ slideshowStart: "Inizia la presentazione",
+ slideshowStop: "Termina la presentazione"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-ja.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-ja.js
new file mode 100644
index 0000000..5480de3
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-ja.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Japanaese (ja)
+ translated by: Hajime Fujimoto
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "{total}枚中{current}枚目",
+ previous: "前",
+ next: "次",
+ close: "閉じる",
+ xhrError: "コンテンツの読み込みに失敗しました",
+ imgError: "画像の読み込みに失敗しました",
+ slideshowStart: "スライドショー開始",
+ slideshowStop: "スライドショー終了"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-kr.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-kr.js
new file mode 100644
index 0000000..b95702b
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-kr.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Korean (kr)
+ translated by: lunareffect
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "총 {total} 중 {current}",
+ previous: "이전",
+ next: "다음",
+ close: "닫기",
+ xhrError: "컨텐츠를 불러오는 데 실패했습니다.",
+ imgError: "이미지를 불러오는 데 실패했습니다.",
+ slideshowStart: "슬라이드쇼 시작",
+ slideshowStop: "슬라이드쇼 중지"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-lt.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-lt.js
new file mode 100644
index 0000000..a513fcf
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-lt.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Lithuanian (lt)
+ translated by: Tomas Norkūnas
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Nuotrauka {current} iš {total}",
+ previous: "Atgal",
+ next: "Pirmyn",
+ close: "Uždaryti",
+ xhrError: "Nepavyko užkrauti turinio.",
+ imgError: "Nepavyko užkrauti nuotraukos.",
+ slideshowStart: "Pradėti automatinę peržiūrą",
+ slideshowStop: "Sustabdyti automatinę peržiūrą"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-lv.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-lv.js
new file mode 100644
index 0000000..e376366
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-lv.js
@@ -0,0 +1,16 @@
+/*
+ jQuery Colorbox language configuration
+ language: Latvian (lv)
+ translated by: Matiss Roberts Treinis
+ site: x0.lv
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "attēls {current} no {total}",
+ previous: "iepriekšējais",
+ next: "nākamais",
+ close: "aizvērt",
+ xhrError: "Neizdevās ielādēt saturu.",
+ imgError: "Neizdevās ielādēt attēlu.",
+ slideshowStart: "sākt slaidrādi",
+ slideshowStop: "apturēt slaidrādi"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-my.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-my.js
new file mode 100644
index 0000000..216e252
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-my.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Myanmar (my)
+ translated by: Yan Naing
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "ပုံ {total} မှာ {current} မြောက်ပုံ",
+ previous: "ရှေ့သို့",
+ next: "နောက်သို့",
+ close: "ပိတ်မည်",
+ xhrError: "ပါဝင်သော အကြောင်းအရာများ ဖော်ပြရာတွင် အနည်းငယ် ချို့ယွင်းမှုရှိနေပါသည်",
+ imgError: "ပုံပြသရာတွင် အနည်းငယ် ချို့ယွင်းချက် ရှိနေပါသည်",
+ slideshowStart: "ပုံများ စတင်ပြသမည်",
+ slideshowStop: "ပုံပြသခြင်း ရပ်ဆိုင်မည်"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-nl.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-nl.js
new file mode 100644
index 0000000..dfc658e
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-nl.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Dutch (nl)
+ translated by: barryvdh
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Afbeelding {current} van {total}",
+ previous: "Vorige",
+ next: "Volgende",
+ close: "Sluiten",
+ xhrError: "Deze inhoud kan niet geladen worden.",
+ imgError: "Deze afbeelding kan niet geladen worden.",
+ slideshowStart: "Diashow starten",
+ slideshowStop: "Diashow stoppen"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-no.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-no.js
new file mode 100644
index 0000000..277c5d3
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-no.js
@@ -0,0 +1,16 @@
+/*
+ jQuery Colorbox language configuration
+ language: Norwegian (no)
+ translated by: lars-erik
+ site: markedspartner.no
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Bilde {current} av {total}",
+ previous: "Forrige",
+ next: "Neste",
+ close: "Lukk",
+ xhrError: "Feil ved lasting av innhold.",
+ imgError: "Feil ved lasting av bilde.",
+ slideshowStart: "Start lysbildefremvisning",
+ slideshowStop: "Stopp lysbildefremvisning"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-pl.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-pl.js
new file mode 100644
index 0000000..1c04dae
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-pl.js
@@ -0,0 +1,16 @@
+/*
+ jQuery Colorbox language configuration
+ language: Polski (pl)
+ translated by: Tomasz Wasiński
+ site: 2bevisible.pl
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "{current}. obrazek z {total}",
+ previous: "Poprzedni",
+ next: "Następny",
+ close: "Zamknij",
+ xhrError: "Nie udało się załadować treści.",
+ imgError: "Nie udało się załadować obrazka.",
+ slideshowStart: "rozpocznij pokaz slajdów",
+ slideshowStop: "zatrzymaj pokaz slajdów"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-pt-br.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-pt-br.js
new file mode 100644
index 0000000..73e948b
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-pt-br.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Brazilian Portuguese (pt-br)
+ translated by: ReinaldoMT
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Imagem {current} de {total}",
+ previous: "Anterior",
+ next: "Próxima",
+ close: "Fechar",
+ slideshowStart: "iniciar apresentação de slides",
+ slideshowStop: "parar apresentação de slides",
+ xhrError: "Erro ao carregar o conteúdo.",
+ imgError: "Erro ao carregar a imagem."
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-ro.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-ro.js
new file mode 100644
index 0000000..0a461e2
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-ro.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Romanian (ro)
+ translated by: shurub3l
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "imagine {current} din {total}",
+ previous: "precedenta",
+ next: "următoarea",
+ close: "închideți",
+ xhrError: "Acest conținut nu poate fi încărcat.",
+ imgError: "Această imagine nu poate fi încărcată",
+ slideshowStart: "începeți prezentarea (slideshow)",
+ slideshowStop: "opriți prezentarea (slideshow)"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-ru.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-ru.js
new file mode 100644
index 0000000..1d88b8c
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-ru.js
@@ -0,0 +1,16 @@
+/*
+ jQuery Colorbox language configuration
+ language: Russian (ru)
+ translated by: Marfa
+ site: themarfa.name
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "изображение {current} из {total}",
+ previous: "назад",
+ next: "вперёд",
+ close: "закрыть",
+ xhrError: "Не удалось загрузить содержимое.",
+ imgError: "Не удалось загрузить изображение.",
+ slideshowStart: "начать слайд-шоу",
+ slideshowStop: "остановить слайд-шоу"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-si.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-si.js
new file mode 100644
index 0000000..034b5b3
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-si.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Slovenian (si)
+ translated by: Boštjan Pišler (pisler.si)
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Slika {current} od {total}",
+ previous: "Prejšnja",
+ next: "Naslednja",
+ close: "Zapri",
+ xhrError: "Vsebine ni bilo mogoče naložiti.",
+ imgError: "Slike ni bilo mogoče naložiti.",
+ slideshowStart: "Zaženi prezentacijo",
+ slideshowStop: "Zaustavi prezentacijo"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-sk.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-sk.js
new file mode 100644
index 0000000..faa9291
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-sk.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Slovak (sk)
+ translated by: Jaroslav Kostal
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "{current}. obrázok z {total}",
+ previous: "Predchádzajúci",
+ next: "Následujúci",
+ close: "Zatvoriť",
+ xhrError: "Obsah sa nepodarilo načítať.",
+ imgError: "Obrázok sa nepodarilo načítať.",
+ slideshowStart: "Spustiť slideshow",
+ slideshowStop: "zastaviť slideshow"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-sr.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-sr.js
new file mode 100644
index 0000000..618e73c
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-sr.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Serbian (sr)
+ translated by: Sasa Stefanovic (baguje.com)
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Slika {current} od {total}",
+ previous: "Prethodna",
+ next: "Sledeća",
+ close: "Zatvori",
+ xhrError: "Neuspešno učitavanje sadržaja.",
+ imgError: "Neuspešno učitavanje slike.",
+ slideshowStart: "Pokreni slideshow",
+ slideshowStop: "Zaustavi slideshow"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-sv.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-sv.js
new file mode 100644
index 0000000..01bb1d8
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-sv.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Swedish (sv)
+ translated by: Mattias Reichel
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Bild {current} av {total}",
+ previous: "Föregående",
+ next: "Nästa",
+ close: "Stäng",
+ xhrError: "Innehållet kunde inte laddas.",
+ imgError: "Den här bilden kunde inte laddas.",
+ slideshowStart: "Starta bildspel",
+ slideshowStop: "Stoppa bildspel"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-tr.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-tr.js
new file mode 100644
index 0000000..d467c2e
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-tr.js
@@ -0,0 +1,19 @@
+/*
+ jQuery Colorbox language configuration
+ language: Turkish (tr)
+ translated by: Caner ÖNCEL
+ site: egonomik.com
+
+ edited by: Sinan Eldem
+ www.sinaneldem.com.tr
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "Görsel {current} / {total}",
+ previous: "Önceki",
+ next: "Sonraki",
+ close: "Kapat",
+ xhrError: "İçerik yüklenirken hata meydana geldi.",
+ imgError: "Resim yüklenirken hata meydana geldi.",
+ slideshowStart: "Slaytı Başlat",
+ slideshowStop: "Slaytı Durdur"
+});
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-uk.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-uk.js
new file mode 100644
index 0000000..3f786d3
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-uk.js
@@ -0,0 +1,16 @@
+/*
+ jQuery ColorBox language configuration
+ language: Ukrainian (uk)
+ translated by: Andrew
+ http://acisoftware.com.ua
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "зображення {current} з {total}",
+ previous: "попереднє",
+ next: "наступне",
+ close: "закрити",
+ xhrError: "Не вдалося завантажити вміст.",
+ imgError: "Не вдалося завантажити зображення.",
+ slideshowStart: "почати слайд-шоу",
+ slideshowStop: "зупинити слайд-шоу"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-CN.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-CN.js
new file mode 100644
index 0000000..770d8ea
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-CN.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Chinese Simplified (zh-CN)
+ translated by: zhao weiming
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "当前图像 {current} 总共 {total}",
+ previous: "前一页",
+ next: "后一页",
+ close: "关闭",
+ xhrError: "此内容无法加载",
+ imgError: "此图片无法加载",
+ slideshowStart: "开始播放幻灯片",
+ slideshowStop: "停止播放幻灯片"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-TW.js b/bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-TW.js
new file mode 100644
index 0000000..b0c4f12
--- /dev/null
+++ b/bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-TW.js
@@ -0,0 +1,15 @@
+/*
+ jQuery Colorbox language configuration
+ language: Chinese Traditional (zh-TW)
+ translated by: Atans Chiu
+*/
+jQuery.extend(jQuery.colorbox.settings, {
+ current: "圖片 {current} 總共 {total}",
+ previous: "上一頁",
+ next: "下一頁",
+ close: "關閉",
+ xhrError: "此內容加載失敗.",
+ imgError: "此圖片加載失敗.",
+ slideshowStart: "開始幻燈片",
+ slideshowStop: "結束幻燈片"
+}); \ No newline at end of file
diff --git a/bower_components/jquery-colorbox/jquery.colorbox.js b/bower_components/jquery-colorbox/jquery.colorbox.js
new file mode 100644
index 0000000..44a90ff
--- /dev/null
+++ b/bower_components/jquery-colorbox/jquery.colorbox.js
@@ -0,0 +1,1090 @@
+/*!
+ Colorbox v1.5.9 - 2014-04-25
+ jQuery lightbox and modal window plugin
+ (c) 2014 Jack Moore - http://www.jacklmoore.com/colorbox
+ license: http://www.opensource.org/licenses/mit-license.php
+*/
+(function ($, document, window) {
+ var
+ // Default settings object.
+ // See http://jacklmoore.com/colorbox for details.
+ defaults = {
+ // data sources
+ html: false,
+ photo: false,
+ iframe: false,
+ inline: false,
+
+ // behavior and appearance
+ transition: "elastic",
+ speed: 300,
+ fadeOut: 300,
+ width: false,
+ initialWidth: "600",
+ innerWidth: false,
+ maxWidth: false,
+ height: false,
+ initialHeight: "450",
+ innerHeight: false,
+ maxHeight: false,
+ scalePhotos: true,
+ scrolling: true,
+ opacity: 0.9,
+ preloading: true,
+ className: false,
+ overlayClose: true,
+ escKey: true,
+ arrowKey: true,
+ top: false,
+ bottom: false,
+ left: false,
+ right: false,
+ fixed: false,
+ data: undefined,
+ closeButton: true,
+ fastIframe: true,
+ open: false,
+ reposition: true,
+ loop: true,
+ slideshow: false,
+ slideshowAuto: true,
+ slideshowSpeed: 2500,
+ slideshowStart: "start slideshow",
+ slideshowStop: "stop slideshow",
+ photoRegex: /\.(gif|png|jp(e|g|eg)|bmp|ico|webp|jxr|svg)((#|\?).*)?$/i,
+
+ // alternate image paths for high-res displays
+ retinaImage: false,
+ retinaUrl: false,
+ retinaSuffix: '@2x.$1',
+
+ // internationalization
+ current: "image {current} of {total}",
+ previous: "previous",
+ next: "next",
+ close: "close",
+ xhrError: "This content failed to load.",
+ imgError: "This image failed to load.",
+
+ // accessbility
+ returnFocus: true,
+ trapFocus: true,
+
+ // callbacks
+ onOpen: false,
+ onLoad: false,
+ onComplete: false,
+ onCleanup: false,
+ onClosed: false,
+
+ rel: function() {
+ return this.rel;
+ },
+ href: function() {
+ // using this.href would give the absolute url, when the href may have been inteded as a selector (e.g. '#container')
+ return $(this).attr('href');
+ },
+ title: function() {
+ return this.title;
+ }
+ },
+
+
+ // Abstracting the HTML and event identifiers for easy rebranding
+ colorbox = 'colorbox',
+ prefix = 'cbox',
+ boxElement = prefix + 'Element',
+
+ // Events
+ event_open = prefix + '_open',
+ event_load = prefix + '_load',
+ event_complete = prefix + '_complete',
+ event_cleanup = prefix + '_cleanup',
+ event_closed = prefix + '_closed',
+ event_purge = prefix + '_purge',
+
+ // Cached jQuery Object Variables
+ $overlay,
+ $box,
+ $wrap,
+ $content,
+ $topBorder,
+ $leftBorder,
+ $rightBorder,
+ $bottomBorder,
+ $related,
+ $window,
+ $loaded,
+ $loadingBay,
+ $loadingOverlay,
+ $title,
+ $current,
+ $slideshow,
+ $next,
+ $prev,
+ $close,
+ $groupControls,
+ $events = $('<a/>'), // $({}) would be prefered, but there is an issue with jQuery 1.4.2
+
+ // Variables for cached values or use across multiple functions
+ settings,
+ interfaceHeight,
+ interfaceWidth,
+ loadedHeight,
+ loadedWidth,
+ index,
+ photo,
+ open,
+ active,
+ closing,
+ loadingTimer,
+ publicMethod,
+ div = "div",
+ requests = 0,
+ previousCSS = {},
+ init;
+
+ // ****************
+ // HELPER FUNCTIONS
+ // ****************
+
+ // Convenience function for creating new jQuery objects
+ function $tag(tag, id, css) {
+ var element = document.createElement(tag);
+
+ if (id) {
+ element.id = prefix + id;
+ }
+
+ if (css) {
+ element.style.cssText = css;
+ }
+
+ return $(element);
+ }
+
+ // Get the window height using innerHeight when available to avoid an issue with iOS
+ // http://bugs.jquery.com/ticket/6724
+ function winheight() {
+ return window.innerHeight ? window.innerHeight : $(window).height();
+ }
+
+ function Settings(element, options) {
+ if (options !== Object(options)) {
+ options = {};
+ }
+
+ this.cache = {};
+ this.el = element;
+
+ this.value = function(key) {
+ var dataAttr;
+
+ if (this.cache[key] === undefined) {
+ dataAttr = $(this.el).attr('data-cbox-'+key);
+
+ if (dataAttr !== undefined) {
+ this.cache[key] = dataAttr;
+ } else if (options[key] !== undefined) {
+ this.cache[key] = options[key];
+ } else if (defaults[key] !== undefined) {
+ this.cache[key] = defaults[key];
+ }
+ }
+
+ return this.cache[key];
+ };
+
+ this.get = function(key) {
+ var value = this.value(key);
+ return $.isFunction(value) ? value.call(this.el, this) : value;
+ };
+ }
+
+ // Determine the next and previous members in a group.
+ function getIndex(increment) {
+ var
+ max = $related.length,
+ newIndex = (index + increment) % max;
+
+ return (newIndex < 0) ? max + newIndex : newIndex;
+ }
+
+ // Convert '%' and 'px' values to integers
+ function setSize(size, dimension) {
+ return Math.round((/%/.test(size) ? ((dimension === 'x' ? $window.width() : winheight()) / 100) : 1) * parseInt(size, 10));
+ }
+
+ // Checks an href to see if it is a photo.
+ // There is a force photo option (photo: true) for hrefs that cannot be matched by the regex.
+ function isImage(settings, url) {
+ return settings.get('photo') || settings.get('photoRegex').test(url);
+ }
+
+ function retinaUrl(settings, url) {
+ return settings.get('retinaUrl') && window.devicePixelRatio > 1 ? url.replace(settings.get('photoRegex'), settings.get('retinaSuffix')) : url;
+ }
+
+ function trapFocus(e) {
+ if ('contains' in $box[0] && !$box[0].contains(e.target) && e.target !== $overlay[0]) {
+ e.stopPropagation();
+ $box.focus();
+ }
+ }
+
+ function setClass(str) {
+ if (setClass.str !== str) {
+ $box.add($overlay).removeClass(setClass.str).addClass(str);
+ setClass.str = str;
+ }
+ }
+
+ function getRelated(rel) {
+ index = 0;
+
+ if (rel && rel !== false) {
+ $related = $('.' + boxElement).filter(function () {
+ var options = $.data(this, colorbox);
+ var settings = new Settings(this, options);
+ return (settings.get('rel') === rel);
+ });
+ index = $related.index(settings.el);
+
+ // Check direct calls to Colorbox.
+ if (index === -1) {
+ $related = $related.add(settings.el);
+ index = $related.length - 1;
+ }
+ } else {
+ $related = $(settings.el);
+ }
+ }
+
+ function trigger(event) {
+ // for external use
+ $(document).trigger(event);
+ // for internal use
+ $events.triggerHandler(event);
+ }
+
+ var slideshow = (function(){
+ var active,
+ className = prefix + "Slideshow_",
+ click = "click." + prefix,
+ timeOut;
+
+ function clear () {
+ clearTimeout(timeOut);
+ }
+
+ function set() {
+ if (settings.get('loop') || $related[index + 1]) {
+ clear();
+ timeOut = setTimeout(publicMethod.next, settings.get('slideshowSpeed'));
+ }
+ }
+
+ function start() {
+ $slideshow
+ .html(settings.get('slideshowStop'))
+ .unbind(click)
+ .one(click, stop);
+
+ $events
+ .bind(event_complete, set)
+ .bind(event_load, clear);
+
+ $box.removeClass(className + "off").addClass(className + "on");
+ }
+
+ function stop() {
+ clear();
+
+ $events
+ .unbind(event_complete, set)
+ .unbind(event_load, clear);
+
+ $slideshow
+ .html(settings.get('slideshowStart'))
+ .unbind(click)
+ .one(click, function () {
+ publicMethod.next();
+ start();
+ });
+
+ $box.removeClass(className + "on").addClass(className + "off");
+ }
+
+ function reset() {
+ active = false;
+ $slideshow.hide();
+ clear();
+ $events
+ .unbind(event_complete, set)
+ .unbind(event_load, clear);
+ $box.removeClass(className + "off " + className + "on");
+ }
+
+ return function(){
+ if (active) {
+ if (!settings.get('slideshow')) {
+ $events.unbind(event_cleanup, reset);
+ reset();
+ }
+ } else {
+ if (settings.get('slideshow') && $related[1]) {
+ active = true;
+ $events.one(event_cleanup, reset);
+ if (settings.get('slideshowAuto')) {
+ start();
+ } else {
+ stop();
+ }
+ $slideshow.show();
+ }
+ }
+ };
+
+ }());
+
+
+ function launch(element) {
+ var options;
+
+ if (!closing) {
+
+ options = $(element).data('colorbox');
+
+ settings = new Settings(element, options);
+
+ getRelated(settings.get('rel'));
+
+ if (!open) {
+ open = active = true; // Prevents the page-change action from queuing up if the visitor holds down the left or right keys.
+
+ setClass(settings.get('className'));
+
+ // Show colorbox so the sizes can be calculated in older versions of jQuery
+ $box.css({visibility:'hidden', display:'block', opacity:''});
+
+ $loaded = $tag(div, 'LoadedContent', 'width:0; height:0; overflow:hidden; visibility:hidden');
+ $content.css({width:'', height:''}).append($loaded);
+
+ // Cache values needed for size calculations
+ interfaceHeight = $topBorder.height() + $bottomBorder.height() + $content.outerHeight(true) - $content.height();
+ interfaceWidth = $leftBorder.width() + $rightBorder.width() + $content.outerWidth(true) - $content.width();
+ loadedHeight = $loaded.outerHeight(true);
+ loadedWidth = $loaded.outerWidth(true);
+
+ // Opens inital empty Colorbox prior to content being loaded.
+ var initialWidth = setSize(settings.get('initialWidth'), 'x');
+ var initialHeight = setSize(settings.get('initialHeight'), 'y');
+ var maxWidth = settings.get('maxWidth');
+ var maxHeight = settings.get('maxHeight');
+
+ settings.w = (maxWidth !== false ? Math.min(initialWidth, setSize(maxWidth, 'x')) : initialWidth) - loadedWidth - interfaceWidth;
+ settings.h = (maxHeight !== false ? Math.min(initialHeight, setSize(maxHeight, 'y')) : initialHeight) - loadedHeight - interfaceHeight;
+
+ $loaded.css({width:'', height:settings.h});
+ publicMethod.position();
+
+ trigger(event_open);
+ settings.get('onOpen');
+
+ $groupControls.add($title).hide();
+
+ $box.focus();
+
+ if (settings.get('trapFocus')) {
+ // Confine focus to the modal
+ // Uses event capturing that is not supported in IE8-
+ if (document.addEventListener) {
+
+ document.addEventListener('focus', trapFocus, true);
+
+ $events.one(event_closed, function () {
+ document.removeEventListener('focus', trapFocus, true);
+ });
+ }
+ }
+
+ // Return focus on closing
+ if (settings.get('returnFocus')) {
+ $events.one(event_closed, function () {
+ $(settings.el).focus();
+ });
+ }
+ }
+
+ $overlay.css({
+ opacity: parseFloat(settings.get('opacity')) || '',
+ cursor: settings.get('overlayClose') ? 'pointer' : '',
+ visibility: 'visible'
+ }).show();
+
+ if (settings.get('closeButton')) {
+ $close.html(settings.get('close')).appendTo($content);
+ } else {
+ $close.appendTo('<div/>'); // replace with .detach() when dropping jQuery < 1.4
+ }
+
+ load();
+ }
+ }
+
+ // Colorbox's markup needs to be added to the DOM prior to being called
+ // so that the browser will go ahead and load the CSS background images.
+ function appendHTML() {
+ if (!$box && document.body) {
+ init = false;
+ $window = $(window);
+ $box = $tag(div).attr({
+ id: colorbox,
+ 'class': $.support.opacity === false ? prefix + 'IE' : '', // class for optional IE8 & lower targeted CSS.
+ role: 'dialog',
+ tabindex: '-1'
+ }).hide();
+ $overlay = $tag(div, "Overlay").hide();
+ $loadingOverlay = $([$tag(div, "LoadingOverlay")[0],$tag(div, "LoadingGraphic")[0]]);
+ $wrap = $tag(div, "Wrapper");
+ $content = $tag(div, "Content").append(
+ $title = $tag(div, "Title"),
+ $current = $tag(div, "Current"),
+ $prev = $('<button type="button"/>').attr({id:prefix+'Previous'}),
+ $next = $('<button type="button"/>').attr({id:prefix+'Next'}),
+ $slideshow = $tag('button', "Slideshow"),
+ $loadingOverlay
+ );
+
+ $close = $('<button type="button"/>').attr({id:prefix+'Close'});
+
+ $wrap.append( // The 3x3 Grid that makes up Colorbox
+ $tag(div).append(
+ $tag(div, "TopLeft"),
+ $topBorder = $tag(div, "TopCenter"),
+ $tag(div, "TopRight")
+ ),
+ $tag(div, false, 'clear:left').append(
+ $leftBorder = $tag(div, "MiddleLeft"),
+ $content,
+ $rightBorder = $tag(div, "MiddleRight")
+ ),
+ $tag(div, false, 'clear:left').append(
+ $tag(div, "BottomLeft"),
+ $bottomBorder = $tag(div, "BottomCenter"),
+ $tag(div, "BottomRight")
+ )
+ ).find('div div').css({'float': 'left'});
+
+ $loadingBay = $tag(div, false, 'position:absolute; width:9999px; visibility:hidden; display:none; max-width:none;');
+
+ $groupControls = $next.add($prev).add($current).add($slideshow);
+
+ $(document.body).append($overlay, $box.append($wrap, $loadingBay));
+ }
+ }
+
+ // Add Colorbox's event bindings
+ function addBindings() {
+ function clickHandler(e) {
+ // ignore non-left-mouse-clicks and clicks modified with ctrl / command, shift, or alt.
+ // See: http://jacklmoore.com/notes/click-events/
+ if (!(e.which > 1 || e.shiftKey || e.altKey || e.metaKey || e.ctrlKey)) {
+ e.preventDefault();
+ launch(this);
+ }
+ }
+
+ if ($box) {
+ if (!init) {
+ init = true;
+
+ // Anonymous functions here keep the public method from being cached, thereby allowing them to be redefined on the fly.
+ $next.click(function () {
+ publicMethod.next();
+ });
+ $prev.click(function () {
+ publicMethod.prev();
+ });
+ $close.click(function () {
+ publicMethod.close();
+ });
+ $overlay.click(function () {
+ if (settings.get('overlayClose')) {
+ publicMethod.close();
+ }
+ });
+
+ // Key Bindings
+ $(document).bind('keydown.' + prefix, function (e) {
+ var key = e.keyCode;
+ if (open && settings.get('escKey') && key === 27) {
+ e.preventDefault();
+ publicMethod.close();
+ }
+ if (open && settings.get('arrowKey') && $related[1] && !e.altKey) {
+ if (key === 37) {
+ e.preventDefault();
+ $prev.click();
+ } else if (key === 39) {
+ e.preventDefault();
+ $next.click();
+ }
+ }
+ });
+
+ if ($.isFunction($.fn.on)) {
+ // For jQuery 1.7+
+ $(document).on('click.'+prefix, '.'+boxElement, clickHandler);
+ } else {
+ // For jQuery 1.3.x -> 1.6.x
+ // This code is never reached in jQuery 1.9, so do not contact me about 'live' being removed.
+ // This is not here for jQuery 1.9, it's here for legacy users.
+ $('.'+boxElement).live('click.'+prefix, clickHandler);
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ // Don't do anything if Colorbox already exists.
+ if ($.colorbox) {
+ return;
+ }
+
+ // Append the HTML when the DOM loads
+ $(appendHTML);
+
+
+ // ****************
+ // PUBLIC FUNCTIONS
+ // Usage format: $.colorbox.close();
+ // Usage from within an iframe: parent.jQuery.colorbox.close();
+ // ****************
+
+ publicMethod = $.fn[colorbox] = $[colorbox] = function (options, callback) {
+ var settings;
+ var $obj = this;
+
+ options = options || {};
+
+ if ($.isFunction($obj)) { // assume a call to $.colorbox
+ $obj = $('<a/>');
+ options.open = true;
+ } else if (!$obj[0]) { // colorbox being applied to empty collection
+ return $obj;
+ }
+
+
+ if (!$obj[0]) { // colorbox being applied to empty collection
+ return $obj;
+ }
+
+ appendHTML();
+
+ if (addBindings()) {
+
+ if (callback) {
+ options.onComplete = callback;
+ }
+
+ $obj.each(function () {
+ var old = $.data(this, colorbox) || {};
+ $.data(this, colorbox, $.extend(old, options));
+ }).addClass(boxElement);
+
+ settings = new Settings($obj[0], options);
+
+ if (settings.get('open')) {
+ launch($obj[0]);
+ }
+ }
+
+ return $obj;
+ };
+
+ publicMethod.position = function (speed, loadedCallback) {
+ var
+ css,
+ top = 0,
+ left = 0,
+ offset = $box.offset(),
+ scrollTop,
+ scrollLeft;
+
+ $window.unbind('resize.' + prefix);
+
+ // remove the modal so that it doesn't influence the document width/height
+ $box.css({top: -9e4, left: -9e4});
+
+ scrollTop = $window.scrollTop();
+ scrollLeft = $window.scrollLeft();
+
+ if (settings.get('fixed')) {
+ offset.top -= scrollTop;
+ offset.left -= scrollLeft;
+ $box.css({position: 'fixed'});
+ } else {
+ top = scrollTop;
+ left = scrollLeft;
+ $box.css({position: 'absolute'});
+ }
+
+ // keeps the top and left positions within the browser's viewport.
+ if (settings.get('right') !== false) {
+ left += Math.max($window.width() - settings.w - loadedWidth - interfaceWidth - setSize(settings.get('right'), 'x'), 0);
+ } else if (settings.get('left') !== false) {
+ left += setSize(settings.get('left'), 'x');
+ } else {
+ left += Math.round(Math.max($window.width() - settings.w - loadedWidth - interfaceWidth, 0) / 2);
+ }
+
+ if (settings.get('bottom') !== false) {
+ top += Math.max(winheight() - settings.h - loadedHeight - interfaceHeight - setSize(settings.get('bottom'), 'y'), 0);
+ } else if (settings.get('top') !== false) {
+ top += setSize(settings.get('top'), 'y');
+ } else {
+ top += Math.round(Math.max(winheight() - settings.h - loadedHeight - interfaceHeight, 0) / 2);
+ }
+
+ $box.css({top: offset.top, left: offset.left, visibility:'visible'});
+
+ // this gives the wrapper plenty of breathing room so it's floated contents can move around smoothly,
+ // but it has to be shrank down around the size of div#colorbox when it's done. If not,
+ // it can invoke an obscure IE bug when using iframes.
+ $wrap[0].style.width = $wrap[0].style.height = "9999px";
+
+ function modalDimensions() {
+ $topBorder[0].style.width = $bottomBorder[0].style.width = $content[0].style.width = (parseInt($box[0].style.width,10) - interfaceWidth)+'px';
+ $content[0].style.height = $leftBorder[0].style.height = $rightBorder[0].style.height = (parseInt($box[0].style.height,10) - interfaceHeight)+'px';
+ }
+
+ css = {width: settings.w + loadedWidth + interfaceWidth, height: settings.h + loadedHeight + interfaceHeight, top: top, left: left};
+
+ // setting the speed to 0 if the content hasn't changed size or position
+ if (speed) {
+ var tempSpeed = 0;
+ $.each(css, function(i){
+ if (css[i] !== previousCSS[i]) {
+ tempSpeed = speed;
+ return;
+ }
+ });
+ speed = tempSpeed;
+ }
+
+ previousCSS = css;
+
+ if (!speed) {
+ $box.css(css);
+ }
+
+ $box.dequeue().animate(css, {
+ duration: speed || 0,
+ complete: function () {
+ modalDimensions();
+
+ active = false;
+
+ // shrink the wrapper down to exactly the size of colorbox to avoid a bug in IE's iframe implementation.
+ $wrap[0].style.width = (settings.w + loadedWidth + interfaceWidth) + "px";
+ $wrap[0].style.height = (settings.h + loadedHeight + interfaceHeight) + "px";
+
+ if (settings.get('reposition')) {
+ setTimeout(function () { // small delay before binding onresize due to an IE8 bug.
+ $window.bind('resize.' + prefix, publicMethod.position);
+ }, 1);
+ }
+
+ if (loadedCallback) {
+ loadedCallback();
+ }
+ },
+ step: modalDimensions
+ });
+ };
+
+ publicMethod.resize = function (options) {
+ var scrolltop;
+
+ if (open) {
+ options = options || {};
+
+ if (options.width) {
+ settings.w = setSize(options.width, 'x') - loadedWidth - interfaceWidth;
+ }
+
+ if (options.innerWidth) {
+ settings.w = setSize(options.innerWidth, 'x');
+ }
+
+ $loaded.css({width: settings.w});
+
+ if (options.height) {
+ settings.h = setSize(options.height, 'y') - loadedHeight - interfaceHeight;
+ }
+
+ if (options.innerHeight) {
+ settings.h = setSize(options.innerHeight, 'y');
+ }
+
+ if (!options.innerHeight && !options.height) {
+ scrolltop = $loaded.scrollTop();
+ $loaded.css({height: "auto"});
+ settings.h = $loaded.height();
+ }
+
+ $loaded.css({height: settings.h});
+
+ if(scrolltop) {
+ $loaded.scrollTop(scrolltop);
+ }
+
+ publicMethod.position(settings.get('transition') === "none" ? 0 : settings.get('speed'));
+ }
+ };
+
+ publicMethod.prep = function (object) {
+ if (!open) {
+ return;
+ }
+
+ var callback, speed = settings.get('transition') === "none" ? 0 : settings.get('speed');
+
+ $loaded.remove();
+
+ $loaded = $tag(div, 'LoadedContent').append(object);
+
+ function getWidth() {
+ settings.w = settings.w || $loaded.width();
+ settings.w = settings.mw && settings.mw < settings.w ? settings.mw : settings.w;
+ return settings.w;
+ }
+ function getHeight() {
+ settings.h = settings.h || $loaded.height();
+ settings.h = settings.mh && settings.mh < settings.h ? settings.mh : settings.h;
+ return settings.h;
+ }
+
+ $loaded.hide()
+ .appendTo($loadingBay.show())// content has to be appended to the DOM for accurate size calculations.
+ .css({width: getWidth(), overflow: settings.get('scrolling') ? 'auto' : 'hidden'})
+ .css({height: getHeight()})// sets the height independently from the width in case the new width influences the value of height.
+ .prependTo($content);
+
+ $loadingBay.hide();
+
+ // floating the IMG removes the bottom line-height and fixed a problem where IE miscalculates the width of the parent element as 100% of the document width.
+
+ $(photo).css({'float': 'none'});
+
+ setClass(settings.get('className'));
+
+ callback = function () {
+ var total = $related.length,
+ iframe,
+ complete;
+
+ if (!open) {
+ return;
+ }
+
+ function removeFilter() { // Needed for IE8 in versions of jQuery prior to 1.7.2
+ if ($.support.opacity === false) {
+ $box[0].style.removeAttribute('filter');
+ }
+ }
+
+ complete = function () {
+ clearTimeout(loadingTimer);
+ $loadingOverlay.hide();
+ trigger(event_complete);
+ settings.get('onComplete');
+ };
+
+
+ $title.html(settings.get('title')).show();
+ $loaded.show();
+
+ if (total > 1) { // handle grouping
+ if (typeof settings.get('current') === "string") {
+ $current.html(settings.get('current').replace('{current}', index + 1).replace('{total}', total)).show();
+ }
+
+ $next[(settings.get('loop') || index < total - 1) ? "show" : "hide"]().html(settings.get('next'));
+ $prev[(settings.get('loop') || index) ? "show" : "hide"]().html(settings.get('previous'));
+
+ slideshow();
+
+ // Preloads images within a rel group
+ if (settings.get('preloading')) {
+ $.each([getIndex(-1), getIndex(1)], function(){
+ var img,
+ i = $related[this],
+ settings = new Settings(i, $.data(i, colorbox)),
+ src = settings.get('href');
+
+ if (src && isImage(settings, src)) {
+ src = retinaUrl(settings, src);
+ img = document.createElement('img');
+ img.src = src;
+ }
+ });
+ }
+ } else {
+ $groupControls.hide();
+ }
+
+ if (settings.get('iframe')) {
+ iframe = document.createElement('iframe');
+
+ if ('frameBorder' in iframe) {
+ iframe.frameBorder = 0;
+ }
+
+ if ('allowTransparency' in iframe) {
+ iframe.allowTransparency = "true";
+ }
+
+ if (!settings.get('scrolling')) {
+ iframe.scrolling = "no";
+ }
+
+ $(iframe)
+ .attr({
+ src: settings.get('href'),
+ name: (new Date()).getTime(), // give the iframe a unique name to prevent caching
+ 'class': prefix + 'Iframe',
+ allowFullScreen : true // allow HTML5 video to go fullscreen
+ })
+ .one('load', complete)
+ .appendTo($loaded);
+
+ $events.one(event_purge, function () {
+ iframe.src = "//about:blank";
+ });
+
+ if (settings.get('fastIframe')) {
+ $(iframe).trigger('load');
+ }
+ } else {
+ complete();
+ }
+
+ if (settings.get('transition') === 'fade') {
+ $box.fadeTo(speed, 1, removeFilter);
+ } else {
+ removeFilter();
+ }
+ };
+
+ if (settings.get('transition') === 'fade') {
+ $box.fadeTo(speed, 0, function () {
+ publicMethod.position(0, callback);
+ });
+ } else {
+ publicMethod.position(speed, callback);
+ }
+ };
+
+ function load () {
+ var href, setResize, prep = publicMethod.prep, $inline, request = ++requests;
+
+ active = true;
+
+ photo = false;
+
+ trigger(event_purge);
+ trigger(event_load);
+ settings.get('onLoad');
+
+ settings.h = settings.get('height') ?
+ setSize(settings.get('height'), 'y') - loadedHeight - interfaceHeight :
+ settings.get('innerHeight') && setSize(settings.get('innerHeight'), 'y');
+
+ settings.w = settings.get('width') ?
+ setSize(settings.get('width'), 'x') - loadedWidth - interfaceWidth :
+ settings.get('innerWidth') && setSize(settings.get('innerWidth'), 'x');
+
+ // Sets the minimum dimensions for use in image scaling
+ settings.mw = settings.w;
+ settings.mh = settings.h;
+
+ // Re-evaluate the minimum width and height based on maxWidth and maxHeight values.
+ // If the width or height exceed the maxWidth or maxHeight, use the maximum values instead.
+ if (settings.get('maxWidth')) {
+ settings.mw = setSize(settings.get('maxWidth'), 'x') - loadedWidth - interfaceWidth;
+ settings.mw = settings.w && settings.w < settings.mw ? settings.w : settings.mw;
+ }
+ if (settings.get('maxHeight')) {
+ settings.mh = setSize(settings.get('maxHeight'), 'y') - loadedHeight - interfaceHeight;
+ settings.mh = settings.h && settings.h < settings.mh ? settings.h : settings.mh;
+ }
+
+ href = settings.get('href');
+
+ loadingTimer = setTimeout(function () {
+ $loadingOverlay.show();
+ }, 100);
+
+ if (settings.get('inline')) {
+ var $target = $(href);
+ // Inserts an empty placeholder where inline content is being pulled from.
+ // An event is bound to put inline content back when Colorbox closes or loads new content.
+ $inline = $('<div>').hide().insertBefore($target);
+
+ $events.one(event_purge, function () {
+ $inline.replaceWith($target);
+ });
+
+ prep($target);
+ } else if (settings.get('iframe')) {
+ // IFrame element won't be added to the DOM until it is ready to be displayed,
+ // to avoid problems with DOM-ready JS that might be trying to run in that iframe.
+ prep(" ");
+ } else if (settings.get('html')) {
+ prep(settings.get('html'));
+ } else if (isImage(settings, href)) {
+
+ href = retinaUrl(settings, href);
+
+ photo = new Image();
+
+ $(photo)
+ .addClass(prefix + 'Photo')
+ .bind('error',function () {
+ prep($tag(div, 'Error').html(settings.get('imgError')));
+ })
+ .one('load', function () {
+ if (request !== requests) {
+ return;
+ }
+
+ // A small pause because some browsers will occassionaly report a
+ // img.width and img.height of zero immediately after the img.onload fires
+ setTimeout(function(){
+ var percent;
+
+ $.each(['alt', 'longdesc', 'aria-describedby'], function(i,val){
+ var attr = $(settings.el).attr(val) || $(settings.el).attr('data-'+val);
+ if (attr) {
+ photo.setAttribute(val, attr);
+ }
+ });
+
+ if (settings.get('retinaImage') && window.devicePixelRatio > 1) {
+ photo.height = photo.height / window.devicePixelRatio;
+ photo.width = photo.width / window.devicePixelRatio;
+ }
+
+ if (settings.get('scalePhotos')) {
+ setResize = function () {
+ photo.height -= photo.height * percent;
+ photo.width -= photo.width * percent;
+ };
+ if (settings.mw && photo.width > settings.mw) {
+ percent = (photo.width - settings.mw) / photo.width;
+ setResize();
+ }
+ if (settings.mh && photo.height > settings.mh) {
+ percent = (photo.height - settings.mh) / photo.height;
+ setResize();
+ }
+ }
+
+ if (settings.h) {
+ photo.style.marginTop = Math.max(settings.mh - photo.height, 0) / 2 + 'px';
+ }
+
+ if ($related[1] && (settings.get('loop') || $related[index + 1])) {
+ photo.style.cursor = 'pointer';
+ photo.onclick = function () {
+ publicMethod.next();
+ };
+ }
+
+ photo.style.width = photo.width + 'px';
+ photo.style.height = photo.height + 'px';
+ prep(photo);
+ }, 1);
+ });
+
+ photo.src = href;
+
+ } else if (href) {
+ $loadingBay.load(href, settings.get('data'), function (data, status) {
+ if (request === requests) {
+ prep(status === 'error' ? $tag(div, 'Error').html(settings.get('xhrError')) : $(this).contents());
+ }
+ });
+ }
+ }
+
+ // Navigates to the next page/image in a set.
+ publicMethod.next = function () {
+ if (!active && $related[1] && (settings.get('loop') || $related[index + 1])) {
+ index = getIndex(1);
+ launch($related[index]);
+ }
+ };
+
+ publicMethod.prev = function () {
+ if (!active && $related[1] && (settings.get('loop') || index)) {
+ index = getIndex(-1);
+ launch($related[index]);
+ }
+ };
+
+ // Note: to use this within an iframe use the following format: parent.jQuery.colorbox.close();
+ publicMethod.close = function () {
+ if (open && !closing) {
+
+ closing = true;
+ open = false;
+ trigger(event_cleanup);
+ settings.get('onCleanup');
+ $window.unbind('.' + prefix);
+ $overlay.fadeTo(settings.get('fadeOut') || 0, 0);
+
+ $box.stop().fadeTo(settings.get('fadeOut') || 0, 0, function () {
+ $box.hide();
+ $overlay.hide();
+ trigger(event_purge);
+ $loaded.remove();
+
+ setTimeout(function () {
+ closing = false;
+ trigger(event_closed);
+ settings.get('onClosed');
+ }, 1);
+ });
+ }
+ };
+
+ // Removes changes Colorbox made to the document, but does not remove the plugin.
+ publicMethod.remove = function () {
+ if (!$box) { return; }
+
+ $box.stop();
+ $.colorbox.close();
+ $box.stop().remove();
+ $overlay.remove();
+ closing = false;
+ $box = null;
+ $('.' + boxElement)
+ .removeData(colorbox)
+ .removeClass(boxElement);
+
+ $(document).unbind('click.'+prefix);
+ };
+
+ // A method for fetching the current element Colorbox is referencing.
+ // returns a jQuery object.
+ publicMethod.element = function () {
+ return $(settings.el);
+ };
+
+ publicMethod.settings = defaults;
+
+}(jQuery, document, window)); \ No newline at end of file
diff --git a/bower_components/jquery/.bower.json b/bower_components/jquery/.bower.json
new file mode 100644
index 0000000..fb1a0fc
--- /dev/null
+++ b/bower_components/jquery/.bower.json
@@ -0,0 +1,37 @@
+{
+ "name": "jquery",
+ "version": "1.11.1",
+ "main": "dist/jquery.js",
+ "license": "MIT",
+ "ignore": [
+ "**/.*",
+ "build",
+ "speed",
+ "test",
+ "*.md",
+ "AUTHORS.txt",
+ "Gruntfile.js",
+ "package.json"
+ ],
+ "devDependencies": {
+ "sizzle": "1.10.19",
+ "requirejs": "2.1.10",
+ "qunit": "1.14.0",
+ "sinon": "1.8.1"
+ },
+ "keywords": [
+ "jquery",
+ "javascript",
+ "library"
+ ],
+ "homepage": "https://github.com/jquery/jquery",
+ "_release": "1.11.1",
+ "_resolution": {
+ "type": "version",
+ "tag": "1.11.1",
+ "commit": "0d5ec2d8ac94a419ee47a39319c43ff9a7326b50"
+ },
+ "_source": "git://github.com/jquery/jquery.git",
+ "_target": "<2.0.0",
+ "_originalSource": "jquery"
+} \ No newline at end of file
diff --git a/nikola/plugins/task/localsearch/MIT-LICENSE.txt b/bower_components/jquery/MIT-LICENSE.txt
index f131068..cdd31b5 100644
--- a/nikola/plugins/task/localsearch/MIT-LICENSE.txt
+++ b/bower_components/jquery/MIT-LICENSE.txt
@@ -1,4 +1,5 @@
-Tipue Search Copyright (c) 2012 Tipue
+Copyright 2014 jQuery Foundation and other contributors
+http://jquery.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/bower_components/jquery/bower.json b/bower_components/jquery/bower.json
new file mode 100644
index 0000000..03fad08
--- /dev/null
+++ b/bower_components/jquery/bower.json
@@ -0,0 +1,27 @@
+{
+ "name": "jquery",
+ "version": "1.11.1",
+ "main": "dist/jquery.js",
+ "license": "MIT",
+ "ignore": [
+ "**/.*",
+ "build",
+ "speed",
+ "test",
+ "*.md",
+ "AUTHORS.txt",
+ "Gruntfile.js",
+ "package.json"
+ ],
+ "devDependencies": {
+ "sizzle": "1.10.19",
+ "requirejs": "2.1.10",
+ "qunit": "1.14.0",
+ "sinon": "1.8.1"
+ },
+ "keywords": [
+ "jquery",
+ "javascript",
+ "library"
+ ]
+}
diff --git a/bower_components/jquery/dist/jquery.js b/bower_components/jquery/dist/jquery.js
new file mode 100644
index 0000000..d4b67f7
--- /dev/null
+++ b/bower_components/jquery/dist/jquery.js
@@ -0,0 +1,10308 @@
+/*!
+ * jQuery JavaScript Library v1.11.1
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-05-01T17:42Z
+ */
+
+(function( global, factory ) {
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+ // For CommonJS and CommonJS-like environments where a proper window is present,
+ // execute the factory and get jQuery
+ // For environments that do not inherently posses a window with a document
+ // (such as Node.js), expose a jQuery-making factory as module.exports
+ // This accentuates the need for the creation of a real window
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//
+
+var deletedIds = [];
+
+var slice = deletedIds.slice;
+
+var concat = deletedIds.concat;
+
+var push = deletedIds.push;
+
+var indexOf = deletedIds.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var support = {};
+
+
+
+var
+ version = "1.11.1",
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ // Need init if jQuery is called (just allow error to be thrown if not included)
+ return new jQuery.fn.init( selector, context );
+ },
+
+ // Support: Android<4.1, IE<9
+ // Make sure we trim BOM and NBSP
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ };
+
+jQuery.fn = jQuery.prototype = {
+ // The current version of jQuery being used
+ jquery: version,
+
+ constructor: jQuery,
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num != null ?
+
+ // Return just the one element from the set
+ ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
+
+ // Return all the elements in a clean array
+ slice.call( this );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+ ret.context = this.context;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: deletedIds.sort,
+ splice: deletedIds.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var src, copyIsArray, copy, name, options, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+
+ // skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( i === length ) {
+ target = this;
+ i--;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+ // Assume jQuery is ready without the ready module
+ isReady: true,
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ noop: function() {},
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ /* jshint eqeqeq: false */
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ // parseFloat NaNs numeric-cast false positives (null|true|false|"")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ isPlainObject: function( obj ) {
+ var key;
+
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Support: IE<9
+ // Handle iteration over inherited properties before own properties.
+ if ( support.ownLast ) {
+ for ( key in obj ) {
+ return hasOwn.call( obj, key );
+ }
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call(obj) ] || "object" :
+ typeof obj;
+ },
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && jQuery.trim( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
+
+ if ( args ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Support: Android<4.1, IE<9
+ trim: function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( indexOf ) {
+ return indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var len = +second.length,
+ j = 0,
+ i = first.length;
+
+ while ( j < len ) {
+ first[ i++ ] = second[ j++ ];
+ }
+
+ // Support: IE<9
+ // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
+ if ( len !== len ) {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, invert ) {
+ var callbackInverse,
+ matches = [],
+ i = 0,
+ length = elems.length,
+ callbackExpect = !invert;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ callbackInverse = !callback( elems[ i ], i );
+ if ( callbackInverse !== callbackExpect ) {
+ matches.push( elems[ i ] );
+ }
+ }
+
+ return matches;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value,
+ i = 0,
+ length = elems.length,
+ isArray = isArraylike( elems ),
+ ret = [];
+
+ // Go through the array, translating each of the items to their new values
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var args, proxy, tmp;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ now: function() {
+ return +( new Date() );
+ },
+
+ // jQuery.support is not used in Core but other projects attach their
+ // properties to it so it needs to exist.
+ support: support
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( type === "function" || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v1.10.19
+ * http://sizzlejs.com/
+ *
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-04-18
+ */
+(function( window ) {
+
+var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ tokenize,
+ compile,
+ select,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + -(new Date()),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ strundefined = typeof undefined,
+ MAX_NEGATIVE = 1 << 31,
+
+ // Instance methods
+ hasOwn = ({}).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ push_native = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf if we can't use a native one
+ indexOf = arr.indexOf || function( elem ) {
+ var i = 0,
+ len = this.length;
+ for ( ; i < len; i++ ) {
+ if ( this[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
+ // Operator (capture 2)
+ "*([*^$|!~]?=)" + whitespace +
+ // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+ "*\\]",
+
+ pseudos = ":(" + characterEncoding + ")(?:\\((" +
+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+ // 1. quoted (capture 3; capture 4 or capture 5)
+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+ // 2. simple (capture 6)
+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+ // 3. anything else (capture 2)
+ ".*" +
+ ")\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+ rescape = /'|\\/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+ funescape = function( _, escaped, escapedWhitespace ) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ // Support: Firefox<24
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ high < 0 ?
+ // BMP codepoint
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ };
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ (arr = slice.call( preferredDoc.childNodes )),
+ preferredDoc.childNodes
+ );
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ push_native.apply( target, slice.call(els) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+ // Can't trust NodeList.length
+ while ( (target[j++] = els[i++]) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var match, elem, m, nodeType,
+ // QSA vars
+ i, groups, old, nid, newContext, newSelector;
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+
+ context = context || document;
+ results = results || [];
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( documentIsHTML && !seed ) {
+
+ // Shortcuts
+ if ( (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document (jQuery #6963)
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // QSA path
+ if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+ nid = old = expando;
+ newContext = context;
+ newSelector = nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + toSelector( groups[i] );
+ }
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key + " " ) > Expr.cacheLength ) {
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return (cache[ key + " " ] = value);
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return !!fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // Remove from its parent by default
+ if ( div.parentNode ) {
+ div.parentNode.removeChild( div );
+ }
+ // release memory in IE
+ div = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split("|"),
+ i = attrs.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[i] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
+ ( ~a.sourceIndex || MAX_NEGATIVE );
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( (cur = cur.nextSibling) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+ return context && typeof context.getElementsByTagName !== strundefined && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var hasCompare,
+ doc = node ? node.ownerDocument || node : preferredDoc,
+ parent = doc.defaultView;
+
+ // If no document and documentElement is available, return
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Set our document
+ document = doc;
+ docElem = doc.documentElement;
+
+ // Support tests
+ documentIsHTML = !isXML( doc );
+
+ // Support: IE>8
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+ // IE6-8 do not support the defaultView property so parent will be undefined
+ if ( parent && parent !== parent.top ) {
+ // IE11 does not have attachEvent, so all must suffer
+ if ( parent.addEventListener ) {
+ parent.addEventListener( "unload", function() {
+ setDocument();
+ }, false );
+ } else if ( parent.attachEvent ) {
+ parent.attachEvent( "onunload", function() {
+ setDocument();
+ });
+ }
+ }
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
+ support.attributes = assert(function( div ) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function( div ) {
+ div.appendChild( doc.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Check if getElementsByClassName can be trusted
+ support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
+ div.innerHTML = "<div class='a'></div><div class='a i'></div>";
+
+ // Support: Safari<4
+ // Catch class over-caching
+ div.firstChild.className = "i";
+ // Support: Opera<10
+ // Catch gEBCN failure to find non-leading classes
+ return div.getElementsByClassName("i").length === 2;
+ });
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert(function( div ) {
+ docElem.appendChild( div ).id = expando;
+ return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+ });
+
+ // ID find and filter
+ if ( support.getById ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [ m ] : [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ // Support: IE6/7
+ // getElementById is not reliable as a find shortcut
+ delete Expr.find["ID"];
+
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== strundefined ) {
+ return context.getElementsByTagName( tag );
+ }
+ } :
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See http://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
+
+ // Support: IE8, Opera 11-12.16
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ // The test attribute must be unknown in Opera but "safe" for WinRT
+ // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if ( div.querySelectorAll("[msallowclip^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function( div ) {
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = doc.createElement("input");
+ input.setAttribute( "type", "hidden" );
+ div.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if ( div.querySelectorAll("[name=d]").length ) {
+ rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
+ docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector) )) ) {
+
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( div, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ });
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+ // Element contains another
+ // Purposefully does not implement inclusive descendent
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test( docElem.contains ) ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ));
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if ( compare ) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+ a.compareDocumentPosition( b ) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if ( compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+ // Choose the first element that is related to our preferred document
+ if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+ return -1;
+ }
+ if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function( a, b ) {
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Parentless nodes are either documents or disconnected
+ if ( !aup || !bup ) {
+ return a === doc ? -1 :
+ b === doc ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( (cur = cur.parentNode) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( (cur = cur.parentNode) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[i] === bp[i] ) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[i], bp[i] ) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+ // Set document vars if needed
+ if ( ( context.ownerDocument || context ) !== document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val !== undefined ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+ // If no nodeType, this is expected to be an array
+ while ( (node = elem[i++]) ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (jQuery #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
+ // nth-* requires argument
+ if ( !match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[6] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[3] ) {
+ match[2] = match[4] || match[5] || "";
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ match[0] = match[0].slice( 0, excess );
+ match[2] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() { return true; } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, what, argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, context, xml ) {
+ var cache, outerCache, node, diff, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( (node = node[ dir ]) ) {
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+ // Seek `elem` from a previously-cached index
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
+ cache = outerCache[ type ] || [];
+ nodeIndex = cache[0] === dirruns && cache[1];
+ diff = cache[0] === dirruns && cache[2];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ // Use previously-cached element index if available
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+ diff = cache[1];
+
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ } else {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf.call( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+ // lang value must be a valid identifier
+ if ( !ridentifier.test(lang || "") ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( (elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+ return false;
+ };
+ }),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeType < 6 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( (tokens = []) );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace( rtrim, " " )
+ });
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ type: type,
+ matches: match
+ });
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[i].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var oldCache, outerCache,
+ newCache = [ dirruns, doneName ];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
+ if ( (oldCache = outerCache[ dir ]) &&
+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return (newCache[ 2 ] = oldCache[ 2 ]);
+ } else {
+ // Reuse newcache so results back-propagate to previous elements
+ outerCache[ dir ] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf.call( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, outermost ) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+ len = elems.length;
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+ for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( (matcher = setMatchers[j++]) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !match ) {
+ match = tokenize( selector );
+ }
+ i = match.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( match[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+
+ // Save selector and tokenization
+ cached.selector = selector;
+ }
+ return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ * selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ * selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ compiled = typeof selector === "function" && selector,
+ match = !seed && tokenize( (selector = compiled.selector || selector) );
+
+ results = results || [];
+
+ // Try to minimize operations if there is no seed and only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ support.getById && context.nodeType === 9 && documentIsHTML &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+ if ( !context ) {
+ return results;
+
+ // Precompiled matchers will still verify ancestry, so step up a level
+ } else if ( compiled ) {
+ context = context.parentNode;
+ }
+
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( runescape, funescape ),
+ rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function if one is not provided
+ // Provide `match` to avoid retokenization if we modified the selector above
+ ( compiled || compile( selector, match ) )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ rsibling.test( selector ) && testContext( context.parentNode ) || context
+ );
+ return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome<14
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+ // Should return 1, but returns 4 (following)
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+ div.innerHTML = "<a href='#'></a>";
+ return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+ div.innerHTML = "<input/>";
+ div.firstChild.setAttribute( "value", "" );
+ return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+ addHandle( "value", function( elem, name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+ return div.getAttribute("disabled") == null;
+}) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return elem[ name ] === true ? name.toLowerCase() :
+ (val = elem.getAttributeNode( name )) && val.specified ?
+ val.value :
+ null;
+ }
+ });
+}
+
+return Sizzle;
+
+})( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
+
+
+
+var risSimple = /^.[^:#\[\.,]*$/;
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ /* jshint -W018 */
+ return !!qualifier.call( elem, i, elem ) !== not;
+ });
+
+ }
+
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ });
+
+ }
+
+ if ( typeof qualifier === "string" ) {
+ if ( risSimple.test( qualifier ) ) {
+ return jQuery.filter( qualifier, elements, not );
+ }
+
+ qualifier = jQuery.filter( qualifier, elements );
+ }
+
+ return jQuery.grep( elements, function( elem ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
+ });
+}
+
+jQuery.filter = function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 && elem.nodeType === 1 ?
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ }));
+};
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var i,
+ ret = [],
+ self = this,
+ len = self.length;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ }) );
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
+ return ret;
+ },
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], false) );
+ },
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], true) );
+ },
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ }
+});
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ init = jQuery.fn.init = function( selector, context ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+
+ // scripts is true for back-compat
+ // Intentionally let the error be thrown if parseHTML is not present
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return typeof rootjQuery.ready !== "undefined" ?
+ rootjQuery.ready( selector ) :
+ // Execute immediately if ready is not present
+ selector( jQuery );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.extend({
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+jQuery.fn.extend({
+ has: function( target ) {
+ var i,
+ targets = jQuery( target, this ),
+ len = targets.length;
+
+ return this.filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ matched = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && (pos ?
+ pos.index(cur) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector(cur, selectors)) ) {
+
+ matched.push( cur );
+ break;
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ return this.pushStack(
+ jQuery.unique(
+ jQuery.merge( this.get(), jQuery( selector, context ) )
+ )
+ );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
+ }
+});
+
+function sibling( cur, dir ) {
+ do {
+ cur = cur[ dir ];
+ } while ( cur && cur.nodeType !== 1 );
+
+ return cur;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ if ( this.length > 1 ) {
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ ret = jQuery.unique( ret );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+ }
+
+ return this.pushStack( ret );
+ };
+});
+var rnotwhite = (/\S+/g);
+
+
+
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ firingLength = 0;
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( list && ( !fired || stack ) ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+ if ( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+
+ } else if ( !(--remaining) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+
+
+// The deferred used on DOM ready
+var readyList;
+
+jQuery.fn.ready = function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+};
+
+jQuery.extend({
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.triggerHandler ) {
+ jQuery( document ).triggerHandler( "ready" );
+ jQuery( document ).off( "ready" );
+ }
+ }
+});
+
+/**
+ * Clean-up method for dom ready events
+ */
+function detach() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", completed, false );
+ window.removeEventListener( "load", completed, false );
+
+ } else {
+ document.detachEvent( "onreadystatechange", completed );
+ window.detachEvent( "onload", completed );
+ }
+}
+
+/**
+ * The ready event handler and self cleanup method
+ */
+function completed() {
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
+ if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
+ detach();
+ jQuery.ready();
+ }
+}
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", completed );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", completed );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // detach all dom ready events
+ detach();
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+
+var strundefined = typeof undefined;
+
+
+
+// Support: IE<9
+// Iteration over object's inherited properties before its own
+var i;
+for ( i in jQuery( support ) ) {
+ break;
+}
+support.ownLast = i !== "0";
+
+// Note: most support tests are defined in their respective modules.
+// false until the test is run
+support.inlineBlockNeedsLayout = false;
+
+// Execute ASAP in case we need to set body.style.zoom
+jQuery(function() {
+ // Minified: var a,b,c,d
+ var val, div, body, container;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ if ( typeof div.style.zoom !== strundefined ) {
+ // Support: IE<8
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
+
+ support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
+ if ( val ) {
+ // Prevent IE 6 from affecting layout for positioned elements #11048
+ // Prevent IE from shrinking the body in IE 7 mode #12869
+ // Support: IE<8
+ body.style.zoom = 1;
+ }
+ }
+
+ body.removeChild( container );
+});
+
+
+
+
+(function() {
+ var div = document.createElement( "div" );
+
+ // Execute the test only if not already executed in another module.
+ if (support.deleteExpando == null) {
+ // Support: IE<9
+ support.deleteExpando = true;
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+ }
+
+ // Null elements to avoid leaks in IE.
+ div = null;
+})();
+
+
+/**
+ * Determines whether an object can have data
+ */
+jQuery.acceptData = function( elem ) {
+ var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ],
+ nodeType = +elem.nodeType || 1;
+
+ // Do not set data on non-element DOM nodes because it will not be cleared (#8335).
+ return nodeType !== 1 && nodeType !== 9 ?
+ false :
+
+ // Nodes accept data unless otherwise specified; rejection can be conditional
+ !noData || noData !== true && elem.getAttribute("classid") === noData;
+};
+
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var ret, thisCache,
+ internalKey = jQuery.expando,
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ // Avoid exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( typeof name === "string" ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i,
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ } else {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+ }
+
+ i = name.length;
+ while ( i-- ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ /* jshint eqeqeq: false */
+ } else if ( support.deleteExpando || cache != cache.window ) {
+ /* jshint eqeqeq: true */
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+}
+
+jQuery.extend({
+ cache: {},
+
+ // The following elements (space-suffixed to avoid Object.prototype collisions)
+ // throw uncatchable exceptions if you attempt to set expando properties
+ noData: {
+ "applet ": true,
+ "embed ": true,
+ // ...but Flash objects (which have this classid) *can* handle expandos
+ "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return internalData( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ return internalRemoveData( elem, name );
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return internalData( elem, name, data, true );
+ },
+
+ _removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, true );
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var i, name, data,
+ elem = this[0],
+ attrs = elem && elem.attributes;
+
+ // Special expections of .data basically thwart jQuery.access,
+ // so implement the relevant behavior ourselves
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ i = attrs.length;
+ while ( i-- ) {
+
+ // Support: IE11+
+ // The attrs elements can be null (#14894)
+ if ( attrs[ i ] ) {
+ name = attrs[ i ].name;
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.slice(5) );
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ return arguments.length > 1 ?
+
+ // Sets one value
+ this.each(function() {
+ jQuery.data( this, key, value );
+ }) :
+
+ // Gets one value
+ // Try to fetch any internally stored data first
+ elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery._removeData( elem, type + "queue" );
+ jQuery._removeData( elem, key );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while ( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var isHidden = function( elem, el ) {
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+ };
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+};
+var rcheckableType = (/^(?:checkbox|radio)$/i);
+
+
+
+(function() {
+ // Minified: var a,b,c
+ var input = document.createElement( "input" ),
+ div = document.createElement( "div" ),
+ fragment = document.createDocumentFragment();
+
+ // Setup
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+
+ // IE strips leading whitespace when .innerHTML is used
+ support.leadingWhitespace = div.firstChild.nodeType === 3;
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ support.tbody = !div.getElementsByTagName( "tbody" ).length;
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ support.html5Clone =
+ document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>";
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ input.type = "checkbox";
+ input.checked = true;
+ fragment.appendChild( input );
+ support.appendChecked = input.checked;
+
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ // Support: IE6-IE11+
+ div.innerHTML = "<textarea>x</textarea>";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ fragment.appendChild( div );
+ div.innerHTML = "<input type='radio' checked='checked' name='t'/>";
+
+ // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
+ // old WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<9
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+ support.noCloneEvent = true;
+ if ( div.attachEvent ) {
+ div.attachEvent( "onclick", function() {
+ support.noCloneEvent = false;
+ });
+
+ div.cloneNode( true ).click();
+ }
+
+ // Execute the test only if not already executed in another module.
+ if (support.deleteExpando == null) {
+ // Support: IE<9
+ support.deleteExpando = true;
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+ }
+})();
+
+
+(function() {
+ var i, eventName,
+ div = document.createElement( "div" );
+
+ // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event)
+ for ( i in { submit: true, change: true, focusin: true }) {
+ eventName = "on" + i;
+
+ if ( !(support[ i + "Bubbles" ] = eventName in window) ) {
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+ div.setAttribute( eventName, "t" );
+ support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false;
+ }
+ }
+
+ // Null elements to avoid leaks in IE.
+ div = null;
+})();
+
+
+var rformElems = /^(?:input|select|textarea)$/i,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+ var tmp, events, t, handleObjIn,
+ special, eventHandle, handleObj,
+ handlers, type, namespaces, origType,
+ elemData = jQuery._data( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+ var j, handleObj, tmp,
+ origCount, t, events,
+ special, handlers, type,
+ namespaces, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery._removeData( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ var handle, ontype, cur,
+ bubbleType, special, tmp, i,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === false ) {
+ event.preventDefault();
+ }
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+ jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ try {
+ elem[ type ]();
+ } catch ( e ) {
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
+ }
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, ret, handleObj, matched, j,
+ handlerQueue = [],
+ args = slice.call( arguments ),
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var sel, handleObj, matches, i,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG <use> instance trees (#13180)
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+ /* jshint eqeqeq: false */
+ for ( ; cur != this; cur = cur.parentNode || this ) {
+ /* jshint eqeqeq: true */
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matches[ sel ] === undefined ) {
+ matches[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matches[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, handlers: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+ }
+
+ return handlerQueue;
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop, copy,
+ type = event.type,
+ originalEvent = event,
+ fixHook = this.fixHooks[ type ];
+
+ if ( !fixHook ) {
+ this.fixHooks[ type ] = fixHook =
+ rmouseEvent.test( type ) ? this.mouseHooks :
+ rkeyEvent.test( type ) ? this.keyHooks :
+ {};
+ }
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = new jQuery.Event( originalEvent );
+
+ i = copy.length;
+ while ( i-- ) {
+ prop = copy[ i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Support: IE<9
+ // Fix target property (#1925)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Support: Chrome 23+, Safari?
+ // Target should not be a text node (#504, #13143)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // Support: IE<9
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
+ event.metaKey = !!event.metaKey;
+
+ return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var body, eventDoc, doc,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ special: {
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ focus: {
+ // Fire native event if possible so blur/focus sequence is correct
+ trigger: function() {
+ if ( this !== safeActiveElement() && this.focus ) {
+ try {
+ this.focus();
+ return false;
+ } catch ( e ) {
+ // Support: IE<9
+ // If we error on focus to hidden element (#1486, #12518),
+ // let .trigger() run the handlers
+ }
+ }
+ },
+ delegateType: "focusin"
+ },
+ blur: {
+ trigger: function() {
+ if ( this === safeActiveElement() && this.blur ) {
+ this.blur();
+ return false;
+ }
+ },
+ delegateType: "focusout"
+ },
+ click: {
+ // For checkbox, fire native event so checked state will be right
+ trigger: function() {
+ if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+ this.click();
+ return false;
+ }
+ },
+
+ // For cross-browser consistency, don't fire native .click() on links
+ _default: function( event ) {
+ return jQuery.nodeName( event.target, "a" );
+ }
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Support: Firefox 20+
+ // Firefox doesn't alert if the returnValue field is not set.
+ if ( event.result !== undefined && event.originalEvent ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ var name = "on" + type;
+
+ if ( elem.detachEvent ) {
+
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
+ if ( typeof elem[ name ] === strundefined ) {
+ elem[ name ] = null;
+ }
+
+ elem.detachEvent( name, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = src.defaultPrevented ||
+ src.defaultPrevented === undefined &&
+ // Support: IE < 9, Android < 4.0
+ src.returnValue === false ?
+ returnTrue :
+ returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+ if ( !e ) {
+ return;
+ }
+
+ // If preventDefault exists, run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // Support: IE
+ // Otherwise set the returnValue property of the original event to false
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+ if ( !e ) {
+ return;
+ }
+ // If stopPropagation exists, run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+
+ // Support: IE
+ // Set the cancelBubble property of the original event to true
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ var e = this.originalEvent;
+
+ this.isImmediatePropagationStopped = returnTrue;
+
+ if ( e && e.stopImmediatePropagation ) {
+ e.stopImmediatePropagation();
+ }
+
+ this.stopPropagation();
+ }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout",
+ pointerenter: "pointerover",
+ pointerleave: "pointerout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// IE submit delegation
+if ( !support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !jQuery._data( form, "submitBubbles" ) ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ jQuery._data( form, "submitBubbles", true );
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
+
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
+ }
+ };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !support.changeBubbles ) {
+
+ jQuery.event.special.change = {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ }
+ // Allow triggered, simulated change events (#11500)
+ jQuery.event.simulate( "change", this, event, true );
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
+
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ jQuery._data( elem, "changeBubbles", true );
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
+ },
+
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return !rformElems.test( this.nodeName );
+ }
+ };
+}
+
+// Create "bubbling" focus and blur events
+if ( !support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler on the document while someone wants focusin/focusout
+ var handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ var doc = this.ownerDocument || this,
+ attaches = jQuery._data( doc, fix );
+
+ if ( !attaches ) {
+ doc.addEventListener( orig, handler, true );
+ }
+ jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this,
+ attaches = jQuery._data( doc, fix ) - 1;
+
+ if ( !attaches ) {
+ doc.removeEventListener( orig, handler, true );
+ jQuery._removeData( doc, fix );
+ } else {
+ jQuery._data( doc, fix, attaches );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var type, origFn;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[0];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+});
+
+
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ rtagName = /<([\w:]+)/,
+ rtbody = /<tbody/i,
+ rhtml = /<|&#?\w+;/,
+ rnoInnerhtml = /<(?:script|style|link)/i,
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /^$|\/(?:java|ecma)script/i,
+ rscriptTypeMasked = /^true\/(.*)/,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+ // We have to close these tags to support XHTML (#13200)
+ wrapMap = {
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
+ area: [ 1, "<map>", "</map>" ],
+ param: [ 1, "<object>", "</object>" ],
+ thead: [ 1, "<table>", "</table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+ // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+ // unless wrapped in a div with non-breaking characters in front of it.
+ _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
+ },
+ safeFragment = createSafeFragment( document ),
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+function getAll( context, tag ) {
+ var elems, elem,
+ i = 0,
+ found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) :
+ typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) :
+ undefined;
+
+ if ( !found ) {
+ for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
+ if ( !tag || jQuery.nodeName( elem, tag ) ) {
+ found.push( elem );
+ } else {
+ jQuery.merge( found, getAll( elem, tag ) );
+ }
+ }
+ }
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], found ) :
+ found;
+}
+
+// Used in buildFragment, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( rcheckableType.test( elem.type ) ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+
+// Support: IE<8
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+ return jQuery.nodeName( elem, "table" ) &&
+ jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
+
+ elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+ elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ var match = rscriptTypeMasked.exec( elem.type );
+ if ( match ) {
+ elem.type = match[1];
+ } else {
+ elem.removeAttribute("type");
+ }
+ return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var elem,
+ i = 0;
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
+ }
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function fixCloneNodeIssues( src, dest ) {
+ var nodeName, e, data;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 copies events bound via attachEvent when using cloneNode.
+ if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
+ data = jQuery._data( dest );
+
+ for ( e in data.events ) {
+ jQuery.removeEvent( dest, e, data.handle );
+ }
+
+ // Event data gets referenced instead of copied if the expando gets copied too
+ dest.removeAttribute( jQuery.expando );
+ }
+
+ // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
+ if ( nodeName === "script" && dest.text !== src.text ) {
+ disableScript( dest ).text = src.text;
+ restoreScript( dest );
+
+ // IE6-10 improperly clones children of object elements using classid.
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
+ } else if ( nodeName === "object" ) {
+ if ( dest.parentNode ) {
+ dest.outerHTML = src.outerHTML;
+ }
+
+ // This path appears unavoidable for IE9. When cloning an object
+ // element in IE9, the outerHTML strategy above is not sufficient.
+ // If the src has innerHTML and the destination does not,
+ // copy the src.innerHTML into the dest.innerHTML. #10324
+ if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
+ dest.innerHTML = src.innerHTML;
+ }
+
+ } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+
+ dest.defaultChecked = dest.checked = src.checked;
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.defaultSelected = dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var destElements, node, clone, i, srcElements,
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+ clone = elem.cloneNode( true );
+
+ // IE<=8 does not properly clone detached, unknown element nodes
+ } else {
+ fragmentDiv.innerHTML = elem.outerHTML;
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+ }
+
+ if ( (!support.noCloneEvent || !support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ // Fix all IE cloning issues
+ for ( i = 0; (node = srcElements[i]) != null; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ fixCloneNodeIssues( node, destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0; (node = srcElements[i]) != null; i++ ) {
+ cloneCopyEvent( node, destElements[i] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ destElements = srcElements = node = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ buildFragment: function( elems, context, scripts, selection ) {
+ var j, elem, contains,
+ tmp, tag, tbody, wrap,
+ l = elems.length,
+
+ // Ensure a safe fragment
+ safe = createSafeFragment( context ),
+
+ nodes = [],
+ i = 0;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || safe.appendChild( context.createElement("div") );
+
+ // Deserialize a standard representation
+ tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+
+ tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
+
+ // Descend through wrappers to the right content
+ j = wrap[0];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Manually add leading whitespace removed by IE
+ if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
+ }
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( !support.tbody ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ elem = tag === "table" && !rtbody.test( elem ) ?
+ tmp.firstChild :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] === "<table>" && !rtbody.test( elem ) ?
+ tmp :
+ 0;
+
+ j = elem && elem.childNodes.length;
+ while ( j-- ) {
+ if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+ elem.removeChild( tbody );
+ }
+ }
+ }
+
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Fix #12392 for WebKit and IE > 9
+ tmp.textContent = "";
+
+ // Fix #12392 for oldIE
+ while ( tmp.firstChild ) {
+ tmp.removeChild( tmp.firstChild );
+ }
+
+ // Remember the top-level container for proper cleanup
+ tmp = safe.lastChild;
+ }
+ }
+ }
+
+ // Fix #11356: Clear elements from fragment
+ if ( tmp ) {
+ safe.removeChild( tmp );
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !support.appendChecked ) {
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+ }
+
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( safe.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ tmp = null;
+
+ return safe;
+ },
+
+ cleanData: function( elems, /* internal */ acceptData ) {
+ var elem, type, id, data,
+ i = 0,
+ internalKey = jQuery.expando,
+ cache = jQuery.cache,
+ deleteExpando = support.deleteExpando,
+ special = jQuery.event.special;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( acceptData || jQuery.acceptData( elem ) ) {
+
+ id = elem[ internalKey ];
+ data = id && cache[ id ];
+
+ if ( data ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Remove cache only if it was not already removed by jQuery.event.remove
+ if ( cache[ id ] ) {
+
+ delete cache[ id ];
+
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( deleteExpando ) {
+ delete elem[ internalKey ];
+
+ } else if ( typeof elem.removeAttribute !== strundefined ) {
+ elem.removeAttribute( internalKey );
+
+ } else {
+ elem[ internalKey ] = null;
+ }
+
+ deletedIds.push( id );
+ }
+ }
+ }
+ }
+ }
+});
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ });
+ },
+
+ after: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ });
+ },
+
+ remove: function( selector, keepData /* Internal Use Only */ ) {
+ var elem,
+ elems = selector ? jQuery.filter( selector, this ) : this,
+ i = 0;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem ) );
+ }
+
+ if ( elem.parentNode ) {
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+ setGlobalEval( getAll( elem, "script" ) );
+ }
+ elem.parentNode.removeChild( elem );
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+
+ // If this is a select, ensure that it displays empty (#12336)
+ // Support: IE<9
+ if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
+ elem.options.length = 0;
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map(function() {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return access( this, function( value ) {
+ var elem = this[ 0 ] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ undefined;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( support.htmlSerialize || !rnoshimcache.test( value ) ) &&
+ ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var arg = arguments[ 0 ];
+
+ // Make the changes, replacing each context element with the new content
+ this.domManip( arguments, function( elem ) {
+ arg = this.parentNode;
+
+ jQuery.cleanData( getAll( this ) );
+
+ if ( arg ) {
+ arg.replaceChild( elem, this );
+ }
+ });
+
+ // Force removal if there was no new content (e.g., from empty arguments)
+ return arg && (arg.length || arg.nodeType) ? this : this.remove();
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, callback ) {
+
+ // Flatten any nested arrays
+ args = concat.apply( [], args );
+
+ var first, node, hasScripts,
+ scripts, doc, fragment,
+ i = 0,
+ l = this.length,
+ set = this,
+ iNoClone = l - 1,
+ value = args[0],
+ isFunction = jQuery.isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( isFunction ||
+ ( l > 1 && typeof value === "string" &&
+ !support.checkClone && rchecked.test( value ) ) ) {
+ return this.each(function( index ) {
+ var self = set.eq( index );
+ if ( isFunction ) {
+ args[0] = value.call( this, index, self.html() );
+ }
+ self.domManip( args, callback );
+ });
+ }
+
+ if ( l ) {
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( this[i], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+ // Optional AJAX dependency, but won't run scripts if not present
+ if ( jQuery._evalUrl ) {
+ jQuery._evalUrl( node.src );
+ }
+ } else {
+ jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
+ }
+ }
+ }
+ }
+
+ // Fix #11809: Avoid leaking memory
+ fragment = first = null;
+ }
+ }
+
+ return this;
+ }
+});
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ i = 0,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone(true);
+ jQuery( insert[i] )[ original ]( elems );
+
+ // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+ push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+
+var iframe,
+ elemdisplay = {};
+
+/**
+ * Retrieve the actual display of a element
+ * @param {String} name nodeName of the element
+ * @param {Object} doc Document object
+ */
+// Called only from within defaultDisplay
+function actualDisplay( name, doc ) {
+ var style,
+ elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+
+ // getDefaultComputedStyle might be reliably used only on attached element
+ display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
+
+ // Use of this method is a temporary fix (more like optmization) until something better comes along,
+ // since it was removed from specification and supported only in FF
+ style.display : jQuery.css( elem[ 0 ], "display" );
+
+ // We don't have any data stored on the element,
+ // so use "detach" method as fast way to get rid of the element
+ elem.detach();
+
+ return display;
+}
+
+/**
+ * Try to determine the default display value of an element
+ * @param {String} nodeName
+ */
+function defaultDisplay( nodeName ) {
+ var doc = document,
+ display = elemdisplay[ nodeName ];
+
+ if ( !display ) {
+ display = actualDisplay( nodeName, doc );
+
+ // If the simple way fails, read from inside an iframe
+ if ( display === "none" || !display ) {
+
+ // Use the already-created iframe if possible
+ iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;
+
+ // Support: IE
+ doc.write();
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+}
+
+
+(function() {
+ var shrinkWrapBlocksVal;
+
+ support.shrinkWrapBlocks = function() {
+ if ( shrinkWrapBlocksVal != null ) {
+ return shrinkWrapBlocksVal;
+ }
+
+ // Will be changed later if needed.
+ shrinkWrapBlocksVal = false;
+
+ // Minified: var b,c,d
+ var div, body, container;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+ // Test fired too early or in an unsupported environment, exit.
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ // Support: IE6
+ // Check if elements with layout shrink-wrap their children
+ if ( typeof div.style.zoom !== strundefined ) {
+ // Reset CSS: box-sizing; display; margin; border
+ div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+ "box-sizing:content-box;display:block;margin:0;border:0;" +
+ "padding:1px;width:1px;zoom:1";
+ div.appendChild( document.createElement( "div" ) ).style.width = "5px";
+ shrinkWrapBlocksVal = div.offsetWidth !== 3;
+ }
+
+ body.removeChild( container );
+
+ return shrinkWrapBlocksVal;
+ };
+
+})();
+var rmargin = (/^margin/);
+
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+
+
+var getStyles, curCSS,
+ rposition = /^(top|right|bottom|left)$/;
+
+if ( window.getComputedStyle ) {
+ getStyles = function( elem ) {
+ return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
+ };
+
+ curCSS = function( elem, name, computed ) {
+ var width, minWidth, maxWidth, ret,
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
+
+ if ( computed ) {
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ // Support: IE
+ // IE returns zIndex value as an integer.
+ return ret === undefined ?
+ ret :
+ ret + "";
+ };
+} else if ( document.documentElement.currentStyle ) {
+ getStyles = function( elem ) {
+ return elem.currentStyle;
+ };
+
+ curCSS = function( elem, name, computed ) {
+ var left, rs, rsLeft, ret,
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+ ret = computed ? computed[ name ] : undefined;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && style[ name ] ) {
+ ret = style[ name ];
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ // but not position css attributes, as those are proportional to the parent element instead
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rs = elem.runtimeStyle;
+ rsLeft = rs && rs.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ rs.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ rs.left = rsLeft;
+ }
+ }
+
+ // Support: IE
+ // IE returns zIndex value as an integer.
+ return ret === undefined ?
+ ret :
+ ret + "" || "auto";
+ };
+}
+
+
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+ // Define the hook, we'll check on the first run if it's really needed.
+ return {
+ get: function() {
+ var condition = conditionFn();
+
+ if ( condition == null ) {
+ // The test was not ready at this point; screw the hook this time
+ // but check again when needed next time.
+ return;
+ }
+
+ if ( condition ) {
+ // Hook not needed (or it's not possible to use it due to missing dependency),
+ // remove it.
+ // Since there are no other hooks for marginRight, remove the whole object.
+ delete this.get;
+ return;
+ }
+
+ // Hook needed; redefine it so that the support test is not executed again.
+
+ return (this.get = hookFn).apply( this, arguments );
+ }
+ };
+}
+
+
+(function() {
+ // Minified: var b,c,d,e,f,g, h,i
+ var div, style, a, pixelPositionVal, boxSizingReliableVal,
+ reliableHiddenOffsetsVal, reliableMarginRightVal;
+
+ // Setup
+ div = document.createElement( "div" );
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+ a = div.getElementsByTagName( "a" )[ 0 ];
+ style = a && a.style;
+
+ // Finish early in limited (non-browser) environments
+ if ( !style ) {
+ return;
+ }
+
+ style.cssText = "float:left;opacity:.5";
+
+ // Support: IE<9
+ // Make sure that element opacity exists (as opposed to filter)
+ support.opacity = style.opacity === "0.5";
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ support.cssFloat = !!style.cssFloat;
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ support.boxSizing = style.boxSizing === "" || style.MozBoxSizing === "" ||
+ style.WebkitBoxSizing === "";
+
+ jQuery.extend(support, {
+ reliableHiddenOffsets: function() {
+ if ( reliableHiddenOffsetsVal == null ) {
+ computeStyleTests();
+ }
+ return reliableHiddenOffsetsVal;
+ },
+
+ boxSizingReliable: function() {
+ if ( boxSizingReliableVal == null ) {
+ computeStyleTests();
+ }
+ return boxSizingReliableVal;
+ },
+
+ pixelPosition: function() {
+ if ( pixelPositionVal == null ) {
+ computeStyleTests();
+ }
+ return pixelPositionVal;
+ },
+
+ // Support: Android 2.3
+ reliableMarginRight: function() {
+ if ( reliableMarginRightVal == null ) {
+ computeStyleTests();
+ }
+ return reliableMarginRightVal;
+ }
+ });
+
+ function computeStyleTests() {
+ // Minified: var b,c,d,j
+ var div, body, container, contents;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+ // Test fired too early or in an unsupported environment, exit.
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
+ "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
+ "border:1px;padding:1px;width:4px;position:absolute";
+
+ // Support: IE<9
+ // Assume reasonable values in the absence of getComputedStyle
+ pixelPositionVal = boxSizingReliableVal = false;
+ reliableMarginRightVal = true;
+
+ // Check for getComputedStyle so that this code is not run in IE<9.
+ if ( window.getComputedStyle ) {
+ pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ boxSizingReliableVal =
+ ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Support: Android 2.3
+ // Div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container (#3333)
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ contents = div.appendChild( document.createElement( "div" ) );
+
+ // Reset CSS: box-sizing; display; margin; border; padding
+ contents.style.cssText = div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+ "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
+ contents.style.marginRight = contents.style.width = "0";
+ div.style.width = "1px";
+
+ reliableMarginRightVal =
+ !parseFloat( ( window.getComputedStyle( contents, null ) || {} ).marginRight );
+ }
+
+ // Support: IE8
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
+ contents = div.getElementsByTagName( "td" );
+ contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none";
+ reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
+ if ( reliableHiddenOffsetsVal ) {
+ contents[ 0 ].style.display = "";
+ contents[ 1 ].style.display = "none";
+ reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
+ }
+
+ body.removeChild( container );
+ }
+
+})();
+
+
+// A method for quickly swapping in/out CSS properties to get correct calculations.
+jQuery.swap = function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+};
+
+
+var
+ ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity\s*=\s*([^)]*)/,
+
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
+ rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: "0",
+ fontWeight: "400"
+ },
+
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function showHide( elements, show ) {
+ var display, elem, hidden,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ values[ index ] = jQuery._data( elem, "olddisplay" );
+ display = elem.style.display;
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+ }
+ } else {
+ hidden = isHidden( elem );
+
+ if ( display && display !== "none" || !hidden ) {
+ jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ }
+
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var valueIsBorderBox = true,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ styles = getStyles( elem ),
+ isBorderBox = support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, styles );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles
+ )
+ ) + "px";
+}
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
+ cssNumber: {
+ "columnCount": true,
+ "fillOpacity": true,
+ "flexGrow": true,
+ "flexShrink": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that null and NaN values aren't set. See: #7116
+ if ( value == null || value !== value ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+ // but it would mean to define eight (for every problematic property) identical functions
+ if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
+ // Support: IE
+ // Swallow errors from 'invalid' CSS values (#5509)
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var num, val, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ }
+});
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
+ jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ }) :
+ getWidthOrHeight( elem, name, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var styles = extra && getStyles( elem );
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ ) : 0
+ );
+ }
+ };
+});
+
+if ( !support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ // if value === "", then remove inline opacity #12685
+ if ( ( value >= 1 || value === "" ) &&
+ jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+ style.removeAttribute ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there is no filter style applied in a css rule or unset inline opacity, we are done
+ if ( value === "" || currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+ function( elem, computed ) {
+ if ( computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
+ }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return access( this, function( elem, name, value ) {
+ var styles, len,
+ map = {},
+ i = 0;
+
+ if ( jQuery.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each(function() {
+ if ( isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || "swing";
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ if ( tween.elem[ tween.prop ] != null &&
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails
+ // so, simple values such as "10px" are parsed to Float.
+ // complex values such as "rotate(1rad)" are returned as is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+ // use step hook for back compat - use cssHook if its there - use .style if its
+ // available and use plain properties where available
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE <=9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p * Math.PI ) / 2;
+ }
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+ fxNow, timerId,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
+ rrun = /queueHooks$/,
+ animationPrefilters = [ defaultPrefilter ],
+ tweeners = {
+ "*": [ function( prop, value ) {
+ var tween = this.createTween( prop, value ),
+ target = tween.cur(),
+ parts = rfxnum.exec( value ),
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+ scale = 1,
+ maxIterations = 20;
+
+ if ( start && start[ 3 ] !== unit ) {
+ // Trust units reported by jQuery.css
+ unit = unit || start[ 3 ];
+
+ // Make sure we update the tween properties later on
+ parts = parts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ start = +target || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ start = start / scale;
+ jQuery.style( tween.elem, prop, start + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+ }
+
+ // Update tween properties
+ if ( parts ) {
+ start = tween.start = +start || +target || 0;
+ tween.unit = unit;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[ 1 ] ?
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+ +parts[ 2 ];
+ }
+
+ return tween;
+ } ]
+ };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout(function() {
+ fxNow = undefined;
+ });
+ return ( fxNow = jQuery.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ attrs = { height: type },
+ i = 0;
+
+ // if we include width, step value is 1 to do all cssExpand values,
+ // if we don't include width, step value is 2 to skip over Left and Right
+ includeWidth = includeWidth ? 1 : 0;
+ for ( ; i < 4 ; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+ // we're done with this property
+ return tween;
+ }
+ }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+ /* jshint validthis: true */
+ var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHidden( elem ),
+ dataShow = jQuery._data( elem, "fxshow" );
+
+ // handle queue: false promises
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always(function() {
+ // doing this makes sure that the complete handler will be called
+ // before this completes
+ anim.always(function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ });
+ });
+ }
+
+ // height/width overflow pass
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ display = jQuery.css( elem, "display" );
+
+ // Test default display if display is currently "none"
+ checkDisplay = display === "none" ?
+ jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
+
+ if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
+ style.display = "inline-block";
+ } else {
+ style.zoom = 1;
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ if ( !support.shrinkWrapBlocks() ) {
+ anim.always(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+ }
+
+ // show/hide pass
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+
+ // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+ if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+ hidden = true;
+ } else {
+ continue;
+ }
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+
+ // Any non-fx value stops us from restoring the original display value
+ } else {
+ display = undefined;
+ }
+ }
+
+ if ( !jQuery.isEmptyObject( orig ) ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = jQuery._data( elem, "fxshow", {} );
+ }
+
+ // store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+ if ( hidden ) {
+ jQuery( elem ).show();
+ } else {
+ anim.done(function() {
+ jQuery( elem ).hide();
+ });
+ }
+ anim.done(function() {
+ var prop;
+ jQuery._removeData( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ });
+ for ( prop in orig ) {
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = tween.start;
+ if ( hidden ) {
+ tween.end = tween.start;
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+ }
+
+ // If this is a noop like .hide().hide(), restore an overwritten display value
+ } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
+ style.display = display;
+ }
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = jQuery.camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( jQuery.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'index' from above because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = animationPrefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+ // don't match elem in the :animated selector
+ delete tick.elem;
+ }),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+ if ( percent < 1 && length ) {
+ return remaining;
+ } else {
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ }
+ },
+ animation = deferred.promise({
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+ // if we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // resolve when we played the last frame
+ // otherwise, reject
+ if ( gotoEnd ) {
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ }),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length ; index++ ) {
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( jQuery.isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ })
+ );
+
+ // attach callbacks from options
+ return animation.progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.split(" ");
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ tweeners[ prop ] = tweeners[ prop ] || [];
+ tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ animationPrefilters.unshift( callback );
+ } else {
+ animationPrefilters.push( callback );
+ }
+ }
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.fn.extend({
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // show any hidden elements after setting opacity to 0
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+ // animate to the value specified
+ .end().animate({ opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || jQuery._data( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each(function() {
+ var index,
+ data = jQuery._data( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // enable finishing flag on private data
+ data.finish = true;
+
+ // empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // turn off finishing flag
+ delete data.finish;
+ });
+ }
+});
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show"),
+ slideUp: genFx("hide"),
+ slideToggle: genFx("toggle"),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ fxNow = jQuery.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ jQuery.timers.push( timer );
+ if ( timer() ) {
+ jQuery.fx.start();
+ } else {
+ jQuery.timers.pop();
+ }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+};
+
+jQuery.fx.stop = function() {
+ clearInterval( timerId );
+ timerId = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+};
+
+
+(function() {
+ // Minified: var a,b,c,d,e
+ var input, div, select, a, opt;
+
+ // Setup
+ div = document.createElement( "div" );
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+ a = div.getElementsByTagName("a")[ 0 ];
+
+ // First batch of tests.
+ select = document.createElement("select");
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px";
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ support.getSetAttribute = div.className !== "t";
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ support.style = /top/.test( a.getAttribute("style") );
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ support.hrefNormalized = a.getAttribute("href") === "/a";
+
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+ support.checkOn = !!input.value;
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ support.optSelected = opt.selected;
+
+ // Tests for enctype support on a form (#6743)
+ support.enctype = !!document.createElement("form").enctype;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Support: IE8 only
+ // Check if we can trust getAttribute("value")
+ input = document.createElement( "input" );
+ input.setAttribute( "value", "" );
+ support.input = input.getAttribute( "value" ) === "";
+
+ // Check if an input maintains its value after becoming a radio
+ input.value = "t";
+ input.setAttribute( "type", "radio" );
+ support.radioValue = input.value === "t";
+})();
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend({
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map( val, function( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+ // Support: IE10-11+
+ // option.text throws exceptions (#14686, #14858)
+ jQuery.trim( jQuery.text( elem ) );
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+
+ if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) {
+
+ // Support: IE6
+ // When new option element is added to select box we need to
+ // force reflow of newly added node in order to workaround delay
+ // of initialization properties
+ try {
+ option.selected = optionSet = true;
+
+ } catch ( _ ) {
+
+ // Will be executed only in IE6
+ option.scrollHeight;
+ }
+
+ } else {
+ option.selected = false;
+ }
+ }
+
+ // Force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+
+ return options;
+ }
+ }
+ }
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ };
+ if ( !support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ // Support: Webkit
+ // "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ };
+ }
+});
+
+
+
+
+var nodeHook, boolHook,
+ attrHandle = jQuery.expr.attrHandle,
+ ruseDefault = /^(?:checked|selected)$/i,
+ getSetAttribute = support.getSetAttribute,
+ getSetInput = support.input;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ }
+});
+
+jQuery.extend({
+ attr: function( elem, name, value ) {
+ var hooks, ret,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === strundefined ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( jQuery.expr.match.bool.test( name ) ) {
+ // Set corresponding property to false
+ if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ elem[ propName ] = false;
+ // Support: IE<9
+ // Also clear defaultChecked/defaultSelected (if appropriate)
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] =
+ elem[ propName ] = false;
+ }
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ } else {
+ jQuery.attr( elem, name, "" );
+ }
+
+ elem.removeAttribute( getSetAttribute ? name : propName );
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to default in case type is set after value during creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ }
+});
+
+// Hook for boolean attributes
+boolHook = {
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ // IE<8 needs the *property* name
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+ // Use defaultChecked and defaultSelected for oldIE
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+ }
+
+ return name;
+ }
+};
+
+// Retrieve booleans specially
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+
+ var getter = attrHandle[ name ] || jQuery.find.attr;
+
+ attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
+ function( elem, name, isXML ) {
+ var ret, handle;
+ if ( !isXML ) {
+ // Avoid an infinite loop by temporarily removing this function from the getter
+ handle = attrHandle[ name ];
+ attrHandle[ name ] = ret;
+ ret = getter( elem, name, isXML ) != null ?
+ name.toLowerCase() :
+ null;
+ attrHandle[ name ] = handle;
+ }
+ return ret;
+ } :
+ function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem[ jQuery.camelCase( "default-" + name ) ] ?
+ name.toLowerCase() :
+ null;
+ }
+ };
+});
+
+// fix oldIE attroperties
+if ( !getSetInput || !getSetAttribute ) {
+ jQuery.attrHooks.value = {
+ set: function( elem, value, name ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ // Does not return so that setAttribute is also used
+ elem.defaultValue = value;
+ } else {
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
+ return nodeHook && nodeHook.set( elem, value, name );
+ }
+ }
+ };
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = {
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ elem.setAttributeNode(
+ (ret = elem.ownerDocument.createAttribute( name ))
+ );
+ }
+
+ ret.value = value += "";
+
+ // Break association with cloned elements by also using setAttribute (#9646)
+ if ( name === "value" || value === elem.getAttribute( name ) ) {
+ return value;
+ }
+ }
+ };
+
+ // Some attributes are constructed with empty-string values when not defined
+ attrHandle.id = attrHandle.name = attrHandle.coords =
+ function( elem, name, isXML ) {
+ var ret;
+ if ( !isXML ) {
+ return (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
+ ret.value :
+ null;
+ }
+ };
+
+ // Fixing value retrieval on a button requires this module
+ jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ if ( ret && ret.specified ) {
+ return ret.value;
+ }
+ },
+ set: nodeHook.set
+ };
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ set: function( elem, value, name ) {
+ nodeHook.set( elem, value === "" ? false : value, name );
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ };
+ });
+}
+
+if ( !support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
+ return elem.style.cssText || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = value + "" );
+ }
+ };
+}
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button|object)$/i,
+ rclickable = /^(?:a|area)$/i;
+
+jQuery.fn.extend({
+ prop: function( name, value ) {
+ return access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ }
+});
+
+jQuery.extend({
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+ ret :
+ ( elem[ name ] = value );
+
+ } else {
+ return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+ ret :
+ elem[ name ];
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ // Use proper attribute retrieval(#12072)
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+ return tabindex ?
+ parseInt( tabindex, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ -1;
+ }
+ }
+ }
+});
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !support.hrefNormalized ) {
+ // href/src property should get the full normalized URL (#10299/#12915)
+ jQuery.each([ "href", "src" ], function( i, name ) {
+ jQuery.propHooks[ name ] = {
+ get: function( elem ) {
+ return elem.getAttribute( name, 4 );
+ }
+ };
+ });
+}
+
+// Support: Safari, IE9+
+// mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ };
+}
+
+jQuery.each([
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// IE6/7 call enctype encoding
+if ( !support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+
+
+
+var rclass = /[\t\r\n\f]/g;
+
+jQuery.fn.extend({
+ addClass: function( value ) {
+ var classes, elem, cur, clazz, j, finalValue,
+ i = 0,
+ len = this.length,
+ proceed = typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
+ });
+ }
+
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+
+ // only assign if different to avoid unneeded rendering.
+ finalValue = jQuery.trim( cur );
+ if ( elem.className !== finalValue ) {
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, clazz, j, finalValue,
+ i = 0,
+ len = this.length,
+ proceed = arguments.length === 0 || typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
+ });
+ }
+ if ( proceed ) {
+ classes = ( value || "" ).match( rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+
+ // only assign if different to avoid unneeded rendering.
+ finalValue = value ? jQuery.trim( cur ) : "";
+ if ( elem.className !== finalValue ) {
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value;
+
+ if ( typeof stateVal === "boolean" && type === "string" ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ classNames = value.match( rnotwhite ) || [];
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( type === strundefined || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // If the element has a class name or if we're passed "false",
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+});
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+});
+
+jQuery.fn.extend({
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ }
+});
+
+
+var nonce = jQuery.now();
+
+var rquery = (/\?/);
+
+
+
+var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
+
+jQuery.parseJSON = function( data ) {
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ // Support: Android 2.3
+ // Workaround failure to string-cast null input
+ return window.JSON.parse( data + "" );
+ }
+
+ var requireNonComma,
+ depth = null,
+ str = jQuery.trim( data + "" );
+
+ // Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
+ // after removing valid tokens
+ return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
+
+ // Force termination if we see a misplaced comma
+ if ( requireNonComma && comma ) {
+ depth = 0;
+ }
+
+ // Perform no more replacements after returning to outermost depth
+ if ( depth === 0 ) {
+ return token;
+ }
+
+ // Commas must not follow "[", "{", or ","
+ requireNonComma = open || comma;
+
+ // Determine new depth
+ // array/object open ("[" or "{"): depth += true - false (increment)
+ // array/object close ("]" or "}"): depth += false - true (decrement)
+ // other cases ("," or primitive): depth += true - true (numeric cast)
+ depth += !close - !open;
+
+ // Remove this token
+ return "";
+ }) ) ?
+ ( Function( "return " + str ) )() :
+ jQuery.error( "Invalid JSON: " + data );
+};
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data, "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+};
+
+
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+
+ rhash = /#.*$/,
+ rts = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
+
+ if ( jQuery.isFunction( func ) ) {
+ // For each dataType in the dataTypeExpression
+ while ( (dataType = dataTypes[i++]) ) {
+ // Prepend if requested
+ if ( dataType.charAt( 0 ) === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+ // Otherwise append
+ } else {
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ });
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var deep, key,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+ var firstDataType, ct, finalDataType, type,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // Remove auto dataType and get content-type in the process
+ while ( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s[ "throws" ] ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
+}
+
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ type: "GET",
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var // Cross-domain detection vars
+ parts,
+ // Loop variable
+ i,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers as string
+ responseHeadersString,
+ // timeout handle
+ timeoutTimer,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ transport,
+ // Response headers
+ responseHeaders,
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks("once memory"),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // The jqXHR state
+ state = 0,
+ // Default abort message
+ strAbort = "canceled",
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match == null ? null : match;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ var lname = name.toLowerCase();
+ if ( !state ) {
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( state < 2 ) {
+ for ( code in map ) {
+ // Lazy-add the new callback in a way that preserves old ones
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ } else {
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
+
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger("ajaxStart");
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ cacheURL = s.url;
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+ s.url = rts.test( cacheURL ) ?
+
+ // If there is already a '_' parameter, set its value
+ cacheURL.replace( rts, "$1_=" + nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
+ }
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout(function() {
+ jqXHR.abort("timeout");
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader("Last-Modified");
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader("etag");
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger("ajaxStop");
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ });
+ };
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
+ jQuery.fn[ type ] = function( fn ) {
+ return this.on( type, fn );
+ };
+});
+
+
+jQuery._evalUrl = function( url ) {
+ return jQuery.ajax({
+ url: url,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+};
+
+
+jQuery.fn.extend({
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ }
+});
+
+
+jQuery.expr.filters.hidden = function( elem ) {
+ // Support: Opera <= 12.12
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
+ (!support.reliableHiddenOffsets() &&
+ ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+};
+
+jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+};
+
+
+
+
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function() {
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ })
+ .filter(function() {
+ var type = this.type;
+ // Use .is(":disabled") so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !rcheckableType.test( type ) );
+ })
+ .map(function( i, elem ) {
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ) {
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?
+ // Support: IE6+
+ function() {
+
+ // XHR cannot access local files, always use ActiveX for that case
+ return !this.isLocal &&
+
+ // Support: IE7-8
+ // oldIE XHR does not support non-RFC2616 methods (#13240)
+ // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
+ // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
+ // Although this check for six methods instead of eight
+ // since IE also does not support "trace" and "connect"
+ /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
+
+ createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+var xhrId = 0,
+ xhrCallbacks = {},
+ xhrSupported = jQuery.ajaxSettings.xhr();
+
+// Support: IE<10
+// Open requests must be manually aborted on unload (#5280)
+if ( window.ActiveXObject ) {
+ jQuery( window ).on( "unload", function() {
+ for ( var key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( undefined, true );
+ }
+ });
+}
+
+// Determine support properties
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = support.ajax = !!xhrSupported;
+
+// Create transport if the browser can provide an xhr
+if ( xhrSupported ) {
+
+ jQuery.ajaxTransport(function( options ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !options.crossDomain || support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+ var i,
+ xhr = options.xhr(),
+ id = ++xhrId;
+
+ // Open the socket
+ xhr.open( options.type, options.url, options.async, options.username, options.password );
+
+ // Apply custom fields if provided
+ if ( options.xhrFields ) {
+ for ( i in options.xhrFields ) {
+ xhr[ i ] = options.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( options.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( options.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !options.crossDomain && !headers["X-Requested-With"] ) {
+ headers["X-Requested-With"] = "XMLHttpRequest";
+ }
+
+ // Set headers
+ for ( i in headers ) {
+ // Support: IE<9
+ // IE's ActiveXObject throws a 'Type Mismatch' exception when setting
+ // request header to a null-value.
+ //
+ // To keep consistent with other XHR implementations, cast the value
+ // to string and ignore `undefined`.
+ if ( headers[ i ] !== undefined ) {
+ xhr.setRequestHeader( i, headers[ i ] + "" );
+ }
+ }
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( options.hasContent && options.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+ var status, statusText, responses;
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+ // Clean up
+ delete xhrCallbacks[ id ];
+ callback = undefined;
+ xhr.onreadystatechange = jQuery.noop;
+
+ // Abort manually if needed
+ if ( isAbort ) {
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ responses = {};
+ status = xhr.status;
+
+ // Support: IE<10
+ // Accessing binary-data responseText throws an exception
+ // (#11426)
+ if ( typeof xhr.responseText === "string" ) {
+ responses.text = xhr.responseText;
+ }
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && options.isLocal && !options.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, xhr.getAllResponseHeaders() );
+ }
+ };
+
+ if ( !options.async ) {
+ // if we're in sync mode we fire the callback
+ callback();
+ } else if ( xhr.readyState === 4 ) {
+ // (IE6 & IE7) if it's in cache and has been
+ // retrieved directly we need to fire the callback
+ setTimeout( callback );
+ } else {
+ // Add to the list of active xhr callbacks
+ xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback( undefined, true );
+ }
+ }
+ };
+ }
+ });
+}
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+ } catch( e ) {}
+}
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /(?:java|ecma)script/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || jQuery("head")[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement("script");
+
+ script.async = true;
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( script.parentNode ) {
+ script.parentNode.removeChild( script );
+ }
+
+ // Dereference the script
+ script = null;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( undefined, true );
+ }
+ }
+ };
+ }
+});
+
+
+
+
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always(function() {
+ // Restore preexisting value
+ window[ callbackName ] = overwritten;
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+ // make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ });
+
+ // Delegate to script
+ return "script";
+ }
+});
+
+
+
+
+// data: string of html
+// context (optional): If specified, the fragment will be created in this context, defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+ if ( scripts && scripts.length ) {
+ jQuery( scripts ).remove();
+ }
+
+ return jQuery.merge( [], parsed.childNodes );
+};
+
+
+// Keep a copy of the old load method
+var _load = jQuery.fn.load;
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+ }
+
+ var selector, response, type,
+ self = this,
+ off = url.indexOf(" ");
+
+ if ( off >= 0 ) {
+ selector = jQuery.trim( url.slice( off, url.length ) );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax({
+ url: url,
+
+ // if "type" variable is undefined, then "GET" method will be used
+ type: type,
+ dataType: "html",
+ data: params
+ }).done(function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ }).complete( callback && function( jqXHR, status ) {
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+ });
+ }
+
+ return this;
+};
+
+
+
+
+jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+};
+
+
+
+
+
+var docElem = window.document.documentElement;
+
+/**
+ * Gets a window from an element
+ */
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+
+jQuery.offset = {
+ setOffset: function( elem, options, i ) {
+ var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+ position = jQuery.css( elem, "position" ),
+ curElem = jQuery( elem ),
+ props = {};
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ curOffset = curElem.offset();
+ curCSSTop = jQuery.css( elem, "top" );
+ curCSSLeft = jQuery.css( elem, "left" );
+ calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+ jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+jQuery.fn.extend({
+ offset: function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var docElem, win,
+ box = { top: 0, left: 0 },
+ elem = this[ 0 ],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return;
+ }
+
+ docElem = doc.documentElement;
+
+ // Make sure it's not a disconnected DOM node
+ if ( !jQuery.contains( docElem, elem ) ) {
+ return box;
+ }
+
+ // If we don't have gBCR, just use 0,0 rather than error
+ // BlackBerry 5, iOS 3 (original iPhone)
+ if ( typeof elem.getBoundingClientRect !== strundefined ) {
+ box = elem.getBoundingClientRect();
+ }
+ win = getWindow( doc );
+ return {
+ top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
+ left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
+ };
+ },
+
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset,
+ parentOffset = { top: 0, left: 0 },
+ elem = this[ 0 ];
+
+ // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+ // we assume that getBoundingClientRect is available when computed position is fixed
+ offset = elem.getBoundingClientRect();
+ } else {
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent();
+
+ // Get correct offsets
+ offset = this.offset();
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+ parentOffset = offsetParent.offset();
+ }
+
+ // Add offsetParent borders
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ }
+
+ // Subtract parent offsets and element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || docElem;
+
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent || docElem;
+ });
+ }
+});
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+ var top = /Y/.test( prop );
+
+ jQuery.fn[ method ] = function( val ) {
+ return access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ win.document.documentElement[ method ] :
+ elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// getComputedStyle returns percent when specified for top/left/bottom/right
+// rather than make the css module depend on the offset module, we just check for it here
+jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+ function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ );
+});
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+ // margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
+ // https://github.com/jquery/jquery/pull/764
+ return elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+ // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable, null );
+ };
+ });
+});
+
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+ return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function() {
+ return jQuery;
+ });
+}
+
+
+
+
+var
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in
+// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === strundefined ) {
+ window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+
+}));
diff --git a/bower_components/jquery/src/ajax.js b/bower_components/jquery/src/ajax.js
new file mode 100644
index 0000000..1b01fd6
--- /dev/null
+++ b/bower_components/jquery/src/ajax.js
@@ -0,0 +1,807 @@
+define([
+ "./core",
+ "./var/rnotwhite",
+ "./ajax/var/nonce",
+ "./ajax/var/rquery",
+ "./core/init",
+ "./ajax/parseJSON",
+ "./ajax/parseXML",
+ "./deferred"
+], function( jQuery, rnotwhite, nonce, rquery ) {
+
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+
+ rhash = /#.*$/,
+ rts = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
+
+ if ( jQuery.isFunction( func ) ) {
+ // For each dataType in the dataTypeExpression
+ while ( (dataType = dataTypes[i++]) ) {
+ // Prepend if requested
+ if ( dataType.charAt( 0 ) === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+ // Otherwise append
+ } else {
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ });
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var deep, key,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+ var firstDataType, ct, finalDataType, type,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // Remove auto dataType and get content-type in the process
+ while ( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s[ "throws" ] ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
+}
+
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ type: "GET",
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var // Cross-domain detection vars
+ parts,
+ // Loop variable
+ i,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers as string
+ responseHeadersString,
+ // timeout handle
+ timeoutTimer,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ transport,
+ // Response headers
+ responseHeaders,
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks("once memory"),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // The jqXHR state
+ state = 0,
+ // Default abort message
+ strAbort = "canceled",
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match == null ? null : match;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ var lname = name.toLowerCase();
+ if ( !state ) {
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( state < 2 ) {
+ for ( code in map ) {
+ // Lazy-add the new callback in a way that preserves old ones
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ } else {
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
+
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger("ajaxStart");
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ cacheURL = s.url;
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+ s.url = rts.test( cacheURL ) ?
+
+ // If there is already a '_' parameter, set its value
+ cacheURL.replace( rts, "$1_=" + nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
+ }
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout(function() {
+ jqXHR.abort("timeout");
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader("Last-Modified");
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader("etag");
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger("ajaxStop");
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ });
+ };
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
+ jQuery.fn[ type ] = function( fn ) {
+ return this.on( type, fn );
+ };
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/ajax/jsonp.js b/bower_components/jquery/src/ajax/jsonp.js
new file mode 100644
index 0000000..ff0d538
--- /dev/null
+++ b/bower_components/jquery/src/ajax/jsonp.js
@@ -0,0 +1,89 @@
+define([
+ "../core",
+ "./var/nonce",
+ "./var/rquery",
+ "../ajax"
+], function( jQuery, nonce, rquery ) {
+
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always(function() {
+ // Restore preexisting value
+ window[ callbackName ] = overwritten;
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+ // make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ });
+
+ // Delegate to script
+ return "script";
+ }
+});
+
+});
diff --git a/bower_components/jquery/src/ajax/load.js b/bower_components/jquery/src/ajax/load.js
new file mode 100644
index 0000000..24ca95e
--- /dev/null
+++ b/bower_components/jquery/src/ajax/load.js
@@ -0,0 +1,75 @@
+define([
+ "../core",
+ "../core/parseHTML",
+ "../ajax",
+ "../traversing",
+ "../manipulation",
+ "../selector",
+ // Optional event/alias dependency
+ "../event/alias"
+], function( jQuery ) {
+
+// Keep a copy of the old load method
+var _load = jQuery.fn.load;
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+ }
+
+ var selector, response, type,
+ self = this,
+ off = url.indexOf(" ");
+
+ if ( off >= 0 ) {
+ selector = jQuery.trim( url.slice( off, url.length ) );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax({
+ url: url,
+
+ // if "type" variable is undefined, then "GET" method will be used
+ type: type,
+ dataType: "html",
+ data: params
+ }).done(function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ }).complete( callback && function( jqXHR, status ) {
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+ });
+ }
+
+ return this;
+};
+
+});
diff --git a/bower_components/jquery/src/ajax/parseJSON.js b/bower_components/jquery/src/ajax/parseJSON.js
new file mode 100644
index 0000000..69b5c83
--- /dev/null
+++ b/bower_components/jquery/src/ajax/parseJSON.js
@@ -0,0 +1,51 @@
+define([
+ "../core"
+], function( jQuery ) {
+
+var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
+
+jQuery.parseJSON = function( data ) {
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ // Support: Android 2.3
+ // Workaround failure to string-cast null input
+ return window.JSON.parse( data + "" );
+ }
+
+ var requireNonComma,
+ depth = null,
+ str = jQuery.trim( data + "" );
+
+ // Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
+ // after removing valid tokens
+ return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
+
+ // Force termination if we see a misplaced comma
+ if ( requireNonComma && comma ) {
+ depth = 0;
+ }
+
+ // Perform no more replacements after returning to outermost depth
+ if ( depth === 0 ) {
+ return token;
+ }
+
+ // Commas must not follow "[", "{", or ","
+ requireNonComma = open || comma;
+
+ // Determine new depth
+ // array/object open ("[" or "{"): depth += true - false (increment)
+ // array/object close ("]" or "}"): depth += false - true (decrement)
+ // other cases ("," or primitive): depth += true - true (numeric cast)
+ depth += !close - !open;
+
+ // Remove this token
+ return "";
+ }) ) ?
+ ( Function( "return " + str ) )() :
+ jQuery.error( "Invalid JSON: " + data );
+};
+
+return jQuery.parseJSON;
+
+});
diff --git a/bower_components/jquery/src/ajax/parseXML.js b/bower_components/jquery/src/ajax/parseXML.js
new file mode 100644
index 0000000..0b92c7a
--- /dev/null
+++ b/bower_components/jquery/src/ajax/parseXML.js
@@ -0,0 +1,31 @@
+define([
+ "../core"
+], function( jQuery ) {
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data, "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+};
+
+return jQuery.parseXML;
+
+});
diff --git a/bower_components/jquery/src/ajax/script.js b/bower_components/jquery/src/ajax/script.js
new file mode 100644
index 0000000..f6598aa
--- /dev/null
+++ b/bower_components/jquery/src/ajax/script.js
@@ -0,0 +1,93 @@
+define([
+ "../core",
+ "../ajax"
+], function( jQuery ) {
+
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /(?:java|ecma)script/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || jQuery("head")[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement("script");
+
+ script.async = true;
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( script.parentNode ) {
+ script.parentNode.removeChild( script );
+ }
+
+ // Dereference the script
+ script = null;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( undefined, true );
+ }
+ }
+ };
+ }
+});
+
+});
diff --git a/bower_components/jquery/src/ajax/var/nonce.js b/bower_components/jquery/src/ajax/var/nonce.js
new file mode 100644
index 0000000..0871aae
--- /dev/null
+++ b/bower_components/jquery/src/ajax/var/nonce.js
@@ -0,0 +1,5 @@
+define([
+ "../../core"
+], function( jQuery ) {
+ return jQuery.now();
+});
diff --git a/bower_components/jquery/src/ajax/var/rquery.js b/bower_components/jquery/src/ajax/var/rquery.js
new file mode 100644
index 0000000..500a77a
--- /dev/null
+++ b/bower_components/jquery/src/ajax/var/rquery.js
@@ -0,0 +1,3 @@
+define(function() {
+ return (/\?/);
+});
diff --git a/bower_components/jquery/src/ajax/xhr.js b/bower_components/jquery/src/ajax/xhr.js
new file mode 100644
index 0000000..0f560f4
--- /dev/null
+++ b/bower_components/jquery/src/ajax/xhr.js
@@ -0,0 +1,196 @@
+define([
+ "../core",
+ "../var/support",
+ "../ajax"
+], function( jQuery, support ) {
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?
+ // Support: IE6+
+ function() {
+
+ // XHR cannot access local files, always use ActiveX for that case
+ return !this.isLocal &&
+
+ // Support: IE7-8
+ // oldIE XHR does not support non-RFC2616 methods (#13240)
+ // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
+ // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
+ // Although this check for six methods instead of eight
+ // since IE also does not support "trace" and "connect"
+ /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
+
+ createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+var xhrId = 0,
+ xhrCallbacks = {},
+ xhrSupported = jQuery.ajaxSettings.xhr();
+
+// Support: IE<10
+// Open requests must be manually aborted on unload (#5280)
+if ( window.ActiveXObject ) {
+ jQuery( window ).on( "unload", function() {
+ for ( var key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( undefined, true );
+ }
+ });
+}
+
+// Determine support properties
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = support.ajax = !!xhrSupported;
+
+// Create transport if the browser can provide an xhr
+if ( xhrSupported ) {
+
+ jQuery.ajaxTransport(function( options ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !options.crossDomain || support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+ var i,
+ xhr = options.xhr(),
+ id = ++xhrId;
+
+ // Open the socket
+ xhr.open( options.type, options.url, options.async, options.username, options.password );
+
+ // Apply custom fields if provided
+ if ( options.xhrFields ) {
+ for ( i in options.xhrFields ) {
+ xhr[ i ] = options.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( options.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( options.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !options.crossDomain && !headers["X-Requested-With"] ) {
+ headers["X-Requested-With"] = "XMLHttpRequest";
+ }
+
+ // Set headers
+ for ( i in headers ) {
+ // Support: IE<9
+ // IE's ActiveXObject throws a 'Type Mismatch' exception when setting
+ // request header to a null-value.
+ //
+ // To keep consistent with other XHR implementations, cast the value
+ // to string and ignore `undefined`.
+ if ( headers[ i ] !== undefined ) {
+ xhr.setRequestHeader( i, headers[ i ] + "" );
+ }
+ }
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( options.hasContent && options.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+ var status, statusText, responses;
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+ // Clean up
+ delete xhrCallbacks[ id ];
+ callback = undefined;
+ xhr.onreadystatechange = jQuery.noop;
+
+ // Abort manually if needed
+ if ( isAbort ) {
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ responses = {};
+ status = xhr.status;
+
+ // Support: IE<10
+ // Accessing binary-data responseText throws an exception
+ // (#11426)
+ if ( typeof xhr.responseText === "string" ) {
+ responses.text = xhr.responseText;
+ }
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && options.isLocal && !options.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, xhr.getAllResponseHeaders() );
+ }
+ };
+
+ if ( !options.async ) {
+ // if we're in sync mode we fire the callback
+ callback();
+ } else if ( xhr.readyState === 4 ) {
+ // (IE6 & IE7) if it's in cache and has been
+ // retrieved directly we need to fire the callback
+ setTimeout( callback );
+ } else {
+ // Add to the list of active xhr callbacks
+ xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback( undefined, true );
+ }
+ }
+ };
+ }
+ });
+}
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+ } catch( e ) {}
+}
+
+});
diff --git a/bower_components/jquery/src/attributes.js b/bower_components/jquery/src/attributes.js
new file mode 100644
index 0000000..0569013
--- /dev/null
+++ b/bower_components/jquery/src/attributes.js
@@ -0,0 +1,11 @@
+define([
+ "./core",
+ "./attributes/val",
+ "./attributes/attr",
+ "./attributes/prop",
+ "./attributes/classes"
+], function( jQuery ) {
+
+// Return jQuery for attributes-only inclusion
+return jQuery;
+});
diff --git a/bower_components/jquery/src/attributes/attr.js b/bower_components/jquery/src/attributes/attr.js
new file mode 100644
index 0000000..47639c9
--- /dev/null
+++ b/bower_components/jquery/src/attributes/attr.js
@@ -0,0 +1,271 @@
+define([
+ "../core",
+ "../var/rnotwhite",
+ "../var/strundefined",
+ "../core/access",
+ "./support",
+ "./val",
+ "../selector"
+], function( jQuery, rnotwhite, strundefined, access, support ) {
+
+var nodeHook, boolHook,
+ attrHandle = jQuery.expr.attrHandle,
+ ruseDefault = /^(?:checked|selected)$/i,
+ getSetAttribute = support.getSetAttribute,
+ getSetInput = support.input;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ }
+});
+
+jQuery.extend({
+ attr: function( elem, name, value ) {
+ var hooks, ret,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === strundefined ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( jQuery.expr.match.bool.test( name ) ) {
+ // Set corresponding property to false
+ if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ elem[ propName ] = false;
+ // Support: IE<9
+ // Also clear defaultChecked/defaultSelected (if appropriate)
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] =
+ elem[ propName ] = false;
+ }
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ } else {
+ jQuery.attr( elem, name, "" );
+ }
+
+ elem.removeAttribute( getSetAttribute ? name : propName );
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to default in case type is set after value during creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ }
+});
+
+// Hook for boolean attributes
+boolHook = {
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ // IE<8 needs the *property* name
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+ // Use defaultChecked and defaultSelected for oldIE
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+ }
+
+ return name;
+ }
+};
+
+// Retrieve booleans specially
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+
+ var getter = attrHandle[ name ] || jQuery.find.attr;
+
+ attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
+ function( elem, name, isXML ) {
+ var ret, handle;
+ if ( !isXML ) {
+ // Avoid an infinite loop by temporarily removing this function from the getter
+ handle = attrHandle[ name ];
+ attrHandle[ name ] = ret;
+ ret = getter( elem, name, isXML ) != null ?
+ name.toLowerCase() :
+ null;
+ attrHandle[ name ] = handle;
+ }
+ return ret;
+ } :
+ function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem[ jQuery.camelCase( "default-" + name ) ] ?
+ name.toLowerCase() :
+ null;
+ }
+ };
+});
+
+// fix oldIE attroperties
+if ( !getSetInput || !getSetAttribute ) {
+ jQuery.attrHooks.value = {
+ set: function( elem, value, name ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ // Does not return so that setAttribute is also used
+ elem.defaultValue = value;
+ } else {
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
+ return nodeHook && nodeHook.set( elem, value, name );
+ }
+ }
+ };
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = {
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ elem.setAttributeNode(
+ (ret = elem.ownerDocument.createAttribute( name ))
+ );
+ }
+
+ ret.value = value += "";
+
+ // Break association with cloned elements by also using setAttribute (#9646)
+ if ( name === "value" || value === elem.getAttribute( name ) ) {
+ return value;
+ }
+ }
+ };
+
+ // Some attributes are constructed with empty-string values when not defined
+ attrHandle.id = attrHandle.name = attrHandle.coords =
+ function( elem, name, isXML ) {
+ var ret;
+ if ( !isXML ) {
+ return (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
+ ret.value :
+ null;
+ }
+ };
+
+ // Fixing value retrieval on a button requires this module
+ jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ if ( ret && ret.specified ) {
+ return ret.value;
+ }
+ },
+ set: nodeHook.set
+ };
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ set: function( elem, value, name ) {
+ nodeHook.set( elem, value === "" ? false : value, name );
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ };
+ });
+}
+
+if ( !support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
+ return elem.style.cssText || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = value + "" );
+ }
+ };
+}
+
+});
diff --git a/bower_components/jquery/src/attributes/classes.js b/bower_components/jquery/src/attributes/classes.js
new file mode 100644
index 0000000..64bc747
--- /dev/null
+++ b/bower_components/jquery/src/attributes/classes.js
@@ -0,0 +1,157 @@
+define([
+ "../core",
+ "../var/rnotwhite",
+ "../var/strundefined",
+ "../core/init"
+], function( jQuery, rnotwhite, strundefined ) {
+
+var rclass = /[\t\r\n\f]/g;
+
+jQuery.fn.extend({
+ addClass: function( value ) {
+ var classes, elem, cur, clazz, j, finalValue,
+ i = 0,
+ len = this.length,
+ proceed = typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
+ });
+ }
+
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+
+ // only assign if different to avoid unneeded rendering.
+ finalValue = jQuery.trim( cur );
+ if ( elem.className !== finalValue ) {
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, clazz, j, finalValue,
+ i = 0,
+ len = this.length,
+ proceed = arguments.length === 0 || typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
+ });
+ }
+ if ( proceed ) {
+ classes = ( value || "" ).match( rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+
+ // only assign if different to avoid unneeded rendering.
+ finalValue = value ? jQuery.trim( cur ) : "";
+ if ( elem.className !== finalValue ) {
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value;
+
+ if ( typeof stateVal === "boolean" && type === "string" ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ classNames = value.match( rnotwhite ) || [];
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( type === strundefined || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // If the element has a class name or if we're passed "false",
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+});
+
+});
diff --git a/bower_components/jquery/src/attributes/prop.js b/bower_components/jquery/src/attributes/prop.js
new file mode 100644
index 0000000..817a1b6
--- /dev/null
+++ b/bower_components/jquery/src/attributes/prop.js
@@ -0,0 +1,134 @@
+define([
+ "../core",
+ "../core/access",
+ "./support"
+], function( jQuery, access, support ) {
+
+var rfocusable = /^(?:input|select|textarea|button|object)$/i,
+ rclickable = /^(?:a|area)$/i;
+
+jQuery.fn.extend({
+ prop: function( name, value ) {
+ return access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ }
+});
+
+jQuery.extend({
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+ ret :
+ ( elem[ name ] = value );
+
+ } else {
+ return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+ ret :
+ elem[ name ];
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ // Use proper attribute retrieval(#12072)
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+ return tabindex ?
+ parseInt( tabindex, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ -1;
+ }
+ }
+ }
+});
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !support.hrefNormalized ) {
+ // href/src property should get the full normalized URL (#10299/#12915)
+ jQuery.each([ "href", "src" ], function( i, name ) {
+ jQuery.propHooks[ name ] = {
+ get: function( elem ) {
+ return elem.getAttribute( name, 4 );
+ }
+ };
+ });
+}
+
+// Support: Safari, IE9+
+// mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ };
+}
+
+jQuery.each([
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// IE6/7 call enctype encoding
+if ( !support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+});
diff --git a/bower_components/jquery/src/attributes/support.js b/bower_components/jquery/src/attributes/support.js
new file mode 100644
index 0000000..3f85d8a
--- /dev/null
+++ b/bower_components/jquery/src/attributes/support.js
@@ -0,0 +1,62 @@
+define([
+ "../var/support"
+], function( support ) {
+
+(function() {
+ // Minified: var a,b,c,d,e
+ var input, div, select, a, opt;
+
+ // Setup
+ div = document.createElement( "div" );
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+ a = div.getElementsByTagName("a")[ 0 ];
+
+ // First batch of tests.
+ select = document.createElement("select");
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px";
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ support.getSetAttribute = div.className !== "t";
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ support.style = /top/.test( a.getAttribute("style") );
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ support.hrefNormalized = a.getAttribute("href") === "/a";
+
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+ support.checkOn = !!input.value;
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ support.optSelected = opt.selected;
+
+ // Tests for enctype support on a form (#6743)
+ support.enctype = !!document.createElement("form").enctype;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Support: IE8 only
+ // Check if we can trust getAttribute("value")
+ input = document.createElement( "input" );
+ input.setAttribute( "value", "" );
+ support.input = input.getAttribute( "value" ) === "";
+
+ // Check if an input maintains its value after becoming a radio
+ input.value = "t";
+ input.setAttribute( "type", "radio" );
+ support.radioValue = input.value === "t";
+})();
+
+return support;
+
+});
diff --git a/bower_components/jquery/src/attributes/val.js b/bower_components/jquery/src/attributes/val.js
new file mode 100644
index 0000000..4a3b0e5
--- /dev/null
+++ b/bower_components/jquery/src/attributes/val.js
@@ -0,0 +1,178 @@
+define([
+ "../core",
+ "./support",
+ "../core/init"
+], function( jQuery, support ) {
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend({
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map( val, function( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+ // Support: IE10-11+
+ // option.text throws exceptions (#14686, #14858)
+ jQuery.trim( jQuery.text( elem ) );
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+
+ if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) {
+
+ // Support: IE6
+ // When new option element is added to select box we need to
+ // force reflow of newly added node in order to workaround delay
+ // of initialization properties
+ try {
+ option.selected = optionSet = true;
+
+ } catch ( _ ) {
+
+ // Will be executed only in IE6
+ option.scrollHeight;
+ }
+
+ } else {
+ option.selected = false;
+ }
+ }
+
+ // Force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+
+ return options;
+ }
+ }
+ }
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ };
+ if ( !support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ // Support: Webkit
+ // "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ };
+ }
+});
+
+});
diff --git a/bower_components/jquery/src/callbacks.js b/bower_components/jquery/src/callbacks.js
new file mode 100644
index 0000000..9d12823
--- /dev/null
+++ b/bower_components/jquery/src/callbacks.js
@@ -0,0 +1,205 @@
+define([
+ "./core",
+ "./var/rnotwhite"
+], function( jQuery, rnotwhite ) {
+
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ firingLength = 0;
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( list && ( !fired || stack ) ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/core.js b/bower_components/jquery/src/core.js
new file mode 100644
index 0000000..d350104
--- /dev/null
+++ b/bower_components/jquery/src/core.js
@@ -0,0 +1,534 @@
+define([
+ "./var/deletedIds",
+ "./var/slice",
+ "./var/concat",
+ "./var/push",
+ "./var/indexOf",
+ "./var/class2type",
+ "./var/toString",
+ "./var/hasOwn",
+ "./var/support"
+], function( deletedIds, slice, concat, push, indexOf, class2type, toString, hasOwn, support ) {
+
+var
+ version = "@VERSION",
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ // Need init if jQuery is called (just allow error to be thrown if not included)
+ return new jQuery.fn.init( selector, context );
+ },
+
+ // Support: Android<4.1, IE<9
+ // Make sure we trim BOM and NBSP
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ };
+
+jQuery.fn = jQuery.prototype = {
+ // The current version of jQuery being used
+ jquery: version,
+
+ constructor: jQuery,
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num != null ?
+
+ // Return just the one element from the set
+ ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
+
+ // Return all the elements in a clean array
+ slice.call( this );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+ ret.context = this.context;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: deletedIds.sort,
+ splice: deletedIds.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var src, copyIsArray, copy, name, options, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+
+ // skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( i === length ) {
+ target = this;
+ i--;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+ // Assume jQuery is ready without the ready module
+ isReady: true,
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ noop: function() {},
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ /* jshint eqeqeq: false */
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ // parseFloat NaNs numeric-cast false positives (null|true|false|"")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ isPlainObject: function( obj ) {
+ var key;
+
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Support: IE<9
+ // Handle iteration over inherited properties before own properties.
+ if ( support.ownLast ) {
+ for ( key in obj ) {
+ return hasOwn.call( obj, key );
+ }
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call(obj) ] || "object" :
+ typeof obj;
+ },
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && jQuery.trim( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
+
+ if ( args ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Support: Android<4.1, IE<9
+ trim: function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( indexOf ) {
+ return indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var len = +second.length,
+ j = 0,
+ i = first.length;
+
+ while ( j < len ) {
+ first[ i++ ] = second[ j++ ];
+ }
+
+ // Support: IE<9
+ // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
+ if ( len !== len ) {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, invert ) {
+ var callbackInverse,
+ matches = [],
+ i = 0,
+ length = elems.length,
+ callbackExpect = !invert;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ callbackInverse = !callback( elems[ i ], i );
+ if ( callbackInverse !== callbackExpect ) {
+ matches.push( elems[ i ] );
+ }
+ }
+
+ return matches;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value,
+ i = 0,
+ length = elems.length,
+ isArray = isArraylike( elems ),
+ ret = [];
+
+ // Go through the array, translating each of the items to their new values
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var args, proxy, tmp;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ now: function() {
+ return +( new Date() );
+ },
+
+ // jQuery.support is not used in Core but other projects attach their
+ // properties to it so it needs to exist.
+ support: support
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( type === "function" || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/core/access.js b/bower_components/jquery/src/core/access.js
new file mode 100644
index 0000000..97b410b
--- /dev/null
+++ b/bower_components/jquery/src/core/access.js
@@ -0,0 +1,60 @@
+define([
+ "../core"
+], function( jQuery ) {
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+};
+
+return access;
+
+});
diff --git a/bower_components/jquery/src/core/init.js b/bower_components/jquery/src/core/init.js
new file mode 100644
index 0000000..f2db547
--- /dev/null
+++ b/bower_components/jquery/src/core/init.js
@@ -0,0 +1,132 @@
+// Initialize a jQuery object
+define([
+ "../core",
+ "./var/rsingleTag",
+ "../traversing/findFilter"
+], function( jQuery, rsingleTag ) {
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ init = jQuery.fn.init = function( selector, context ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+
+ // scripts is true for back-compat
+ // Intentionally let the error be thrown if parseHTML is not present
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return typeof rootjQuery.ready !== "undefined" ?
+ rootjQuery.ready( selector ) :
+ // Execute immediately if ready is not present
+ selector( jQuery );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+return init;
+
+});
diff --git a/bower_components/jquery/src/core/parseHTML.js b/bower_components/jquery/src/core/parseHTML.js
new file mode 100644
index 0000000..64cf2a1
--- /dev/null
+++ b/bower_components/jquery/src/core/parseHTML.js
@@ -0,0 +1,39 @@
+define([
+ "../core",
+ "./var/rsingleTag",
+ "../manipulation" // buildFragment
+], function( jQuery, rsingleTag ) {
+
+// data: string of html
+// context (optional): If specified, the fragment will be created in this context, defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+ if ( scripts && scripts.length ) {
+ jQuery( scripts ).remove();
+ }
+
+ return jQuery.merge( [], parsed.childNodes );
+};
+
+return jQuery.parseHTML;
+
+});
diff --git a/bower_components/jquery/src/core/ready.js b/bower_components/jquery/src/core/ready.js
new file mode 100644
index 0000000..392c484
--- /dev/null
+++ b/bower_components/jquery/src/core/ready.js
@@ -0,0 +1,152 @@
+define([
+ "../core",
+ "../core/init",
+ "../deferred"
+], function( jQuery ) {
+
+// The deferred used on DOM ready
+var readyList;
+
+jQuery.fn.ready = function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+};
+
+jQuery.extend({
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.triggerHandler ) {
+ jQuery( document ).triggerHandler( "ready" );
+ jQuery( document ).off( "ready" );
+ }
+ }
+});
+
+/**
+ * Clean-up method for dom ready events
+ */
+function detach() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", completed, false );
+ window.removeEventListener( "load", completed, false );
+
+ } else {
+ document.detachEvent( "onreadystatechange", completed );
+ window.detachEvent( "onload", completed );
+ }
+}
+
+/**
+ * The ready event handler and self cleanup method
+ */
+function completed() {
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
+ if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
+ detach();
+ jQuery.ready();
+ }
+}
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", completed );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", completed );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // detach all dom ready events
+ detach();
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+});
diff --git a/bower_components/jquery/src/core/var/rsingleTag.js b/bower_components/jquery/src/core/var/rsingleTag.js
new file mode 100644
index 0000000..7e7090b
--- /dev/null
+++ b/bower_components/jquery/src/core/var/rsingleTag.js
@@ -0,0 +1,4 @@
+define(function() {
+ // Match a standalone tag
+ return (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
+});
diff --git a/bower_components/jquery/src/css.js b/bower_components/jquery/src/css.js
new file mode 100644
index 0000000..2c88f2b
--- /dev/null
+++ b/bower_components/jquery/src/css.js
@@ -0,0 +1,504 @@
+define([
+ "./core",
+ "./var/pnum",
+ "./core/access",
+ "./css/var/rmargin",
+ "./css/var/rnumnonpx",
+ "./css/var/cssExpand",
+ "./css/var/isHidden",
+ "./css/curCSS",
+ "./css/defaultDisplay",
+ "./css/addGetHookIf",
+ "./css/support",
+
+ "./core/init",
+ "./css/swap",
+ "./core/ready",
+ "./selector" // contains
+], function( jQuery, pnum, access, rmargin, rnumnonpx, cssExpand, isHidden,
+ curCSS, defaultDisplay, addGetHookIf, support ) {
+
+var
+ // BuildExclude
+ getStyles = curCSS.getStyles,
+ ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity\s*=\s*([^)]*)/,
+
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
+ rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: "0",
+ fontWeight: "400"
+ },
+
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// BuildExclude
+curCSS = curCSS.curCSS;
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function showHide( elements, show ) {
+ var display, elem, hidden,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ values[ index ] = jQuery._data( elem, "olddisplay" );
+ display = elem.style.display;
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+ }
+ } else {
+ hidden = isHidden( elem );
+
+ if ( display && display !== "none" || !hidden ) {
+ jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ }
+
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var valueIsBorderBox = true,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ styles = getStyles( elem ),
+ isBorderBox = support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, styles );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles
+ )
+ ) + "px";
+}
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
+ cssNumber: {
+ "columnCount": true,
+ "fillOpacity": true,
+ "flexGrow": true,
+ "flexShrink": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that null and NaN values aren't set. See: #7116
+ if ( value == null || value !== value ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+ // but it would mean to define eight (for every problematic property) identical functions
+ if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
+ // Support: IE
+ // Swallow errors from 'invalid' CSS values (#5509)
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var num, val, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ }
+});
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
+ jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ }) :
+ getWidthOrHeight( elem, name, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var styles = extra && getStyles( elem );
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ ) : 0
+ );
+ }
+ };
+});
+
+if ( !support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ // if value === "", then remove inline opacity #12685
+ if ( ( value >= 1 || value === "" ) &&
+ jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+ style.removeAttribute ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there is no filter style applied in a css rule or unset inline opacity, we are done
+ if ( value === "" || currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+ function( elem, computed ) {
+ if ( computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
+ }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return access( this, function( elem, name, value ) {
+ var styles, len,
+ map = {},
+ i = 0;
+
+ if ( jQuery.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each(function() {
+ if ( isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/css/addGetHookIf.js b/bower_components/jquery/src/css/addGetHookIf.js
new file mode 100644
index 0000000..7efcbc8
--- /dev/null
+++ b/bower_components/jquery/src/css/addGetHookIf.js
@@ -0,0 +1,32 @@
+define(function() {
+
+function addGetHookIf( conditionFn, hookFn ) {
+ // Define the hook, we'll check on the first run if it's really needed.
+ return {
+ get: function() {
+ var condition = conditionFn();
+
+ if ( condition == null ) {
+ // The test was not ready at this point; screw the hook this time
+ // but check again when needed next time.
+ return;
+ }
+
+ if ( condition ) {
+ // Hook not needed (or it's not possible to use it due to missing dependency),
+ // remove it.
+ // Since there are no other hooks for marginRight, remove the whole object.
+ delete this.get;
+ return;
+ }
+
+ // Hook needed; redefine it so that the support test is not executed again.
+
+ return (this.get = hookFn).apply( this, arguments );
+ }
+ };
+}
+
+return addGetHookIf;
+
+});
diff --git a/bower_components/jquery/src/css/curCSS.js b/bower_components/jquery/src/css/curCSS.js
new file mode 100644
index 0000000..1f3b734
--- /dev/null
+++ b/bower_components/jquery/src/css/curCSS.js
@@ -0,0 +1,117 @@
+define([
+ "exports",
+ "../core",
+ "./var/rnumnonpx",
+ "./var/rmargin",
+ "../selector" // contains
+], function( exports, jQuery, rnumnonpx, rmargin ) {
+
+var getStyles, curCSS,
+ rposition = /^(top|right|bottom|left)$/;
+
+if ( window.getComputedStyle ) {
+ getStyles = function( elem ) {
+ return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
+ };
+
+ curCSS = function( elem, name, computed ) {
+ var width, minWidth, maxWidth, ret,
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
+
+ if ( computed ) {
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ // Support: IE
+ // IE returns zIndex value as an integer.
+ return ret === undefined ?
+ ret :
+ ret + "";
+ };
+} else if ( document.documentElement.currentStyle ) {
+ getStyles = function( elem ) {
+ return elem.currentStyle;
+ };
+
+ curCSS = function( elem, name, computed ) {
+ var left, rs, rsLeft, ret,
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+ ret = computed ? computed[ name ] : undefined;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && style[ name ] ) {
+ ret = style[ name ];
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ // but not position css attributes, as those are proportional to the parent element instead
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rs = elem.runtimeStyle;
+ rsLeft = rs && rs.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ rs.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ rs.left = rsLeft;
+ }
+ }
+
+ // Support: IE
+ // IE returns zIndex value as an integer.
+ return ret === undefined ?
+ ret :
+ ret + "" || "auto";
+ };
+}
+
+exports.getStyles = getStyles;
+exports.curCSS = curCSS;
+
+});
diff --git a/bower_components/jquery/src/css/defaultDisplay.js b/bower_components/jquery/src/css/defaultDisplay.js
new file mode 100644
index 0000000..210ad4a
--- /dev/null
+++ b/bower_components/jquery/src/css/defaultDisplay.js
@@ -0,0 +1,69 @@
+define([
+ "../core",
+ "../manipulation" // appendTo
+], function( jQuery ) {
+
+var iframe,
+ elemdisplay = {};
+
+/**
+ * Retrieve the actual display of a element
+ * @param {String} name nodeName of the element
+ * @param {Object} doc Document object
+ */
+// Called only from within defaultDisplay
+function actualDisplay( name, doc ) {
+ var style,
+ elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+
+ // getDefaultComputedStyle might be reliably used only on attached element
+ display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
+
+ // Use of this method is a temporary fix (more like optmization) until something better comes along,
+ // since it was removed from specification and supported only in FF
+ style.display : jQuery.css( elem[ 0 ], "display" );
+
+ // We don't have any data stored on the element,
+ // so use "detach" method as fast way to get rid of the element
+ elem.detach();
+
+ return display;
+}
+
+/**
+ * Try to determine the default display value of an element
+ * @param {String} nodeName
+ */
+function defaultDisplay( nodeName ) {
+ var doc = document,
+ display = elemdisplay[ nodeName ];
+
+ if ( !display ) {
+ display = actualDisplay( nodeName, doc );
+
+ // If the simple way fails, read from inside an iframe
+ if ( display === "none" || !display ) {
+
+ // Use the already-created iframe if possible
+ iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;
+
+ // Support: IE
+ doc.write();
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+}
+
+return defaultDisplay;
+});
diff --git a/bower_components/jquery/src/css/hiddenVisibleSelectors.js b/bower_components/jquery/src/css/hiddenVisibleSelectors.js
new file mode 100644
index 0000000..0bd86c8
--- /dev/null
+++ b/bower_components/jquery/src/css/hiddenVisibleSelectors.js
@@ -0,0 +1,20 @@
+define([
+ "../core",
+ "./support",
+ "../selector",
+ "../css"
+], function( jQuery, support ) {
+
+jQuery.expr.filters.hidden = function( elem ) {
+ // Support: Opera <= 12.12
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
+ (!support.reliableHiddenOffsets() &&
+ ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+};
+
+jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+};
+
+});
diff --git a/bower_components/jquery/src/css/support.js b/bower_components/jquery/src/css/support.js
new file mode 100644
index 0000000..4a8fc87
--- /dev/null
+++ b/bower_components/jquery/src/css/support.js
@@ -0,0 +1,149 @@
+define([
+ "../core",
+ "../var/support"
+], function( jQuery, support ) {
+
+(function() {
+ // Minified: var b,c,d,e,f,g, h,i
+ var div, style, a, pixelPositionVal, boxSizingReliableVal,
+ reliableHiddenOffsetsVal, reliableMarginRightVal;
+
+ // Setup
+ div = document.createElement( "div" );
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+ a = div.getElementsByTagName( "a" )[ 0 ];
+ style = a && a.style;
+
+ // Finish early in limited (non-browser) environments
+ if ( !style ) {
+ return;
+ }
+
+ style.cssText = "float:left;opacity:.5";
+
+ // Support: IE<9
+ // Make sure that element opacity exists (as opposed to filter)
+ support.opacity = style.opacity === "0.5";
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ support.cssFloat = !!style.cssFloat;
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ support.boxSizing = style.boxSizing === "" || style.MozBoxSizing === "" ||
+ style.WebkitBoxSizing === "";
+
+ jQuery.extend(support, {
+ reliableHiddenOffsets: function() {
+ if ( reliableHiddenOffsetsVal == null ) {
+ computeStyleTests();
+ }
+ return reliableHiddenOffsetsVal;
+ },
+
+ boxSizingReliable: function() {
+ if ( boxSizingReliableVal == null ) {
+ computeStyleTests();
+ }
+ return boxSizingReliableVal;
+ },
+
+ pixelPosition: function() {
+ if ( pixelPositionVal == null ) {
+ computeStyleTests();
+ }
+ return pixelPositionVal;
+ },
+
+ // Support: Android 2.3
+ reliableMarginRight: function() {
+ if ( reliableMarginRightVal == null ) {
+ computeStyleTests();
+ }
+ return reliableMarginRightVal;
+ }
+ });
+
+ function computeStyleTests() {
+ // Minified: var b,c,d,j
+ var div, body, container, contents;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+ // Test fired too early or in an unsupported environment, exit.
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
+ "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
+ "border:1px;padding:1px;width:4px;position:absolute";
+
+ // Support: IE<9
+ // Assume reasonable values in the absence of getComputedStyle
+ pixelPositionVal = boxSizingReliableVal = false;
+ reliableMarginRightVal = true;
+
+ // Check for getComputedStyle so that this code is not run in IE<9.
+ if ( window.getComputedStyle ) {
+ pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ boxSizingReliableVal =
+ ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Support: Android 2.3
+ // Div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container (#3333)
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ contents = div.appendChild( document.createElement( "div" ) );
+
+ // Reset CSS: box-sizing; display; margin; border; padding
+ contents.style.cssText = div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+ "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
+ contents.style.marginRight = contents.style.width = "0";
+ div.style.width = "1px";
+
+ reliableMarginRightVal =
+ !parseFloat( ( window.getComputedStyle( contents, null ) || {} ).marginRight );
+ }
+
+ // Support: IE8
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
+ contents = div.getElementsByTagName( "td" );
+ contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none";
+ reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
+ if ( reliableHiddenOffsetsVal ) {
+ contents[ 0 ].style.display = "";
+ contents[ 1 ].style.display = "none";
+ reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
+ }
+
+ body.removeChild( container );
+ }
+
+})();
+
+return support;
+
+});
diff --git a/bower_components/jquery/src/css/swap.js b/bower_components/jquery/src/css/swap.js
new file mode 100644
index 0000000..ce16435
--- /dev/null
+++ b/bower_components/jquery/src/css/swap.js
@@ -0,0 +1,28 @@
+define([
+ "../core"
+], function( jQuery ) {
+
+// A method for quickly swapping in/out CSS properties to get correct calculations.
+jQuery.swap = function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+};
+
+return jQuery.swap;
+
+});
diff --git a/bower_components/jquery/src/css/var/cssExpand.js b/bower_components/jquery/src/css/var/cssExpand.js
new file mode 100644
index 0000000..91e90a8
--- /dev/null
+++ b/bower_components/jquery/src/css/var/cssExpand.js
@@ -0,0 +1,3 @@
+define(function() {
+ return [ "Top", "Right", "Bottom", "Left" ];
+});
diff --git a/bower_components/jquery/src/css/var/isHidden.js b/bower_components/jquery/src/css/var/isHidden.js
new file mode 100644
index 0000000..15ab81a
--- /dev/null
+++ b/bower_components/jquery/src/css/var/isHidden.js
@@ -0,0 +1,13 @@
+define([
+ "../../core",
+ "../../selector"
+ // css is assumed
+], function( jQuery ) {
+
+ return function( elem, el ) {
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+ };
+});
diff --git a/bower_components/jquery/src/css/var/rmargin.js b/bower_components/jquery/src/css/var/rmargin.js
new file mode 100644
index 0000000..da0438d
--- /dev/null
+++ b/bower_components/jquery/src/css/var/rmargin.js
@@ -0,0 +1,3 @@
+define(function() {
+ return (/^margin/);
+});
diff --git a/bower_components/jquery/src/css/var/rnumnonpx.js b/bower_components/jquery/src/css/var/rnumnonpx.js
new file mode 100644
index 0000000..c93be28
--- /dev/null
+++ b/bower_components/jquery/src/css/var/rnumnonpx.js
@@ -0,0 +1,5 @@
+define([
+ "../../var/pnum"
+], function( pnum ) {
+ return new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+});
diff --git a/bower_components/jquery/src/data.js b/bower_components/jquery/src/data.js
new file mode 100644
index 0000000..612d91b
--- /dev/null
+++ b/bower_components/jquery/src/data.js
@@ -0,0 +1,335 @@
+define([
+ "./core",
+ "./var/deletedIds",
+ "./data/support",
+ "./data/accepts"
+], function( jQuery, deletedIds, support ) {
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var ret, thisCache,
+ internalKey = jQuery.expando,
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ // Avoid exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( typeof name === "string" ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i,
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ } else {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+ }
+
+ i = name.length;
+ while ( i-- ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ /* jshint eqeqeq: false */
+ } else if ( support.deleteExpando || cache != cache.window ) {
+ /* jshint eqeqeq: true */
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+}
+
+jQuery.extend({
+ cache: {},
+
+ // The following elements (space-suffixed to avoid Object.prototype collisions)
+ // throw uncatchable exceptions if you attempt to set expando properties
+ noData: {
+ "applet ": true,
+ "embed ": true,
+ // ...but Flash objects (which have this classid) *can* handle expandos
+ "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return internalData( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ return internalRemoveData( elem, name );
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return internalData( elem, name, data, true );
+ },
+
+ _removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, true );
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var i, name, data,
+ elem = this[0],
+ attrs = elem && elem.attributes;
+
+ // Special expections of .data basically thwart jQuery.access,
+ // so implement the relevant behavior ourselves
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ i = attrs.length;
+ while ( i-- ) {
+
+ // Support: IE11+
+ // The attrs elements can be null (#14894)
+ if ( attrs[ i ] ) {
+ name = attrs[ i ].name;
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.slice(5) );
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ return arguments.length > 1 ?
+
+ // Sets one value
+ this.each(function() {
+ jQuery.data( this, key, value );
+ }) :
+
+ // Gets one value
+ // Try to fetch any internally stored data first
+ elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/data/accepts.js b/bower_components/jquery/src/data/accepts.js
new file mode 100644
index 0000000..6e0b1b5
--- /dev/null
+++ b/bower_components/jquery/src/data/accepts.js
@@ -0,0 +1,21 @@
+define([
+ "../core"
+], function( jQuery ) {
+
+/**
+ * Determines whether an object can have data
+ */
+jQuery.acceptData = function( elem ) {
+ var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ],
+ nodeType = +elem.nodeType || 1;
+
+ // Do not set data on non-element DOM nodes because it will not be cleared (#8335).
+ return nodeType !== 1 && nodeType !== 9 ?
+ false :
+
+ // Nodes accept data unless otherwise specified; rejection can be conditional
+ !noData || noData !== true && elem.getAttribute("classid") === noData;
+};
+
+return jQuery.acceptData;
+});
diff --git a/bower_components/jquery/src/data/support.js b/bower_components/jquery/src/data/support.js
new file mode 100644
index 0000000..e57f6f7
--- /dev/null
+++ b/bower_components/jquery/src/data/support.js
@@ -0,0 +1,25 @@
+define([
+ "../var/support"
+], function( support ) {
+
+(function() {
+ var div = document.createElement( "div" );
+
+ // Execute the test only if not already executed in another module.
+ if (support.deleteExpando == null) {
+ // Support: IE<9
+ support.deleteExpando = true;
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+ }
+
+ // Null elements to avoid leaks in IE.
+ div = null;
+})();
+
+return support;
+
+});
diff --git a/bower_components/jquery/src/deferred.js b/bower_components/jquery/src/deferred.js
new file mode 100644
index 0000000..8dedbf7
--- /dev/null
+++ b/bower_components/jquery/src/deferred.js
@@ -0,0 +1,150 @@
+define([
+ "./core",
+ "./var/slice",
+ "./callbacks"
+], function( jQuery, slice ) {
+
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+ if ( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+
+ } else if ( !(--remaining) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/deprecated.js b/bower_components/jquery/src/deprecated.js
new file mode 100644
index 0000000..1b068bc
--- /dev/null
+++ b/bower_components/jquery/src/deprecated.js
@@ -0,0 +1,13 @@
+define([
+ "./core",
+ "./traversing"
+], function( jQuery ) {
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+ return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+});
diff --git a/bower_components/jquery/src/dimensions.js b/bower_components/jquery/src/dimensions.js
new file mode 100644
index 0000000..5898832
--- /dev/null
+++ b/bower_components/jquery/src/dimensions.js
@@ -0,0 +1,50 @@
+define([
+ "./core",
+ "./core/access",
+ "./css"
+], function( jQuery, access ) {
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+ // margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
+ // https://github.com/jquery/jquery/pull/764
+ return elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+ // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable, null );
+ };
+ });
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/effects.js b/bower_components/jquery/src/effects.js
new file mode 100644
index 0000000..0469eef
--- /dev/null
+++ b/bower_components/jquery/src/effects.js
@@ -0,0 +1,656 @@
+define([
+ "./core",
+ "./var/pnum",
+ "./css/var/cssExpand",
+ "./css/var/isHidden",
+ "./css/defaultDisplay",
+ "./effects/support",
+
+ "./core/init",
+ "./effects/Tween",
+ "./queue",
+ "./css",
+ "./deferred",
+ "./traversing"
+], function( jQuery, pnum, cssExpand, isHidden, defaultDisplay, support ) {
+
+var
+ fxNow, timerId,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
+ rrun = /queueHooks$/,
+ animationPrefilters = [ defaultPrefilter ],
+ tweeners = {
+ "*": [ function( prop, value ) {
+ var tween = this.createTween( prop, value ),
+ target = tween.cur(),
+ parts = rfxnum.exec( value ),
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+ scale = 1,
+ maxIterations = 20;
+
+ if ( start && start[ 3 ] !== unit ) {
+ // Trust units reported by jQuery.css
+ unit = unit || start[ 3 ];
+
+ // Make sure we update the tween properties later on
+ parts = parts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ start = +target || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ start = start / scale;
+ jQuery.style( tween.elem, prop, start + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+ }
+
+ // Update tween properties
+ if ( parts ) {
+ start = tween.start = +start || +target || 0;
+ tween.unit = unit;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[ 1 ] ?
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+ +parts[ 2 ];
+ }
+
+ return tween;
+ } ]
+ };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout(function() {
+ fxNow = undefined;
+ });
+ return ( fxNow = jQuery.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ attrs = { height: type },
+ i = 0;
+
+ // if we include width, step value is 1 to do all cssExpand values,
+ // if we don't include width, step value is 2 to skip over Left and Right
+ includeWidth = includeWidth ? 1 : 0;
+ for ( ; i < 4 ; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+ // we're done with this property
+ return tween;
+ }
+ }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+ /* jshint validthis: true */
+ var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHidden( elem ),
+ dataShow = jQuery._data( elem, "fxshow" );
+
+ // handle queue: false promises
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always(function() {
+ // doing this makes sure that the complete handler will be called
+ // before this completes
+ anim.always(function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ });
+ });
+ }
+
+ // height/width overflow pass
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ display = jQuery.css( elem, "display" );
+
+ // Test default display if display is currently "none"
+ checkDisplay = display === "none" ?
+ jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
+
+ if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
+ style.display = "inline-block";
+ } else {
+ style.zoom = 1;
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ if ( !support.shrinkWrapBlocks() ) {
+ anim.always(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+ }
+
+ // show/hide pass
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+
+ // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+ if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+ hidden = true;
+ } else {
+ continue;
+ }
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+
+ // Any non-fx value stops us from restoring the original display value
+ } else {
+ display = undefined;
+ }
+ }
+
+ if ( !jQuery.isEmptyObject( orig ) ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = jQuery._data( elem, "fxshow", {} );
+ }
+
+ // store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+ if ( hidden ) {
+ jQuery( elem ).show();
+ } else {
+ anim.done(function() {
+ jQuery( elem ).hide();
+ });
+ }
+ anim.done(function() {
+ var prop;
+ jQuery._removeData( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ });
+ for ( prop in orig ) {
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = tween.start;
+ if ( hidden ) {
+ tween.end = tween.start;
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+ }
+
+ // If this is a noop like .hide().hide(), restore an overwritten display value
+ } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
+ style.display = display;
+ }
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = jQuery.camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( jQuery.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'index' from above because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = animationPrefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+ // don't match elem in the :animated selector
+ delete tick.elem;
+ }),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+ if ( percent < 1 && length ) {
+ return remaining;
+ } else {
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ }
+ },
+ animation = deferred.promise({
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+ // if we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // resolve when we played the last frame
+ // otherwise, reject
+ if ( gotoEnd ) {
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ }),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length ; index++ ) {
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( jQuery.isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ })
+ );
+
+ // attach callbacks from options
+ return animation.progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.split(" ");
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ tweeners[ prop ] = tweeners[ prop ] || [];
+ tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ animationPrefilters.unshift( callback );
+ } else {
+ animationPrefilters.push( callback );
+ }
+ }
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.fn.extend({
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // show any hidden elements after setting opacity to 0
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+ // animate to the value specified
+ .end().animate({ opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || jQuery._data( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each(function() {
+ var index,
+ data = jQuery._data( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // enable finishing flag on private data
+ data.finish = true;
+
+ // empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // turn off finishing flag
+ delete data.finish;
+ });
+ }
+});
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show"),
+ slideUp: genFx("hide"),
+ slideToggle: genFx("toggle"),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ fxNow = jQuery.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ jQuery.timers.push( timer );
+ if ( timer() ) {
+ jQuery.fx.start();
+ } else {
+ jQuery.timers.pop();
+ }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+};
+
+jQuery.fx.stop = function() {
+ clearInterval( timerId );
+ timerId = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+};
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/effects/Tween.js b/bower_components/jquery/src/effects/Tween.js
new file mode 100644
index 0000000..12eec55
--- /dev/null
+++ b/bower_components/jquery/src/effects/Tween.js
@@ -0,0 +1,114 @@
+define([
+ "../core",
+ "../css"
+], function( jQuery ) {
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || "swing";
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ if ( tween.elem[ tween.prop ] != null &&
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails
+ // so, simple values such as "10px" are parsed to Float.
+ // complex values such as "rotate(1rad)" are returned as is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+ // use step hook for back compat - use cssHook if its there - use .style if its
+ // available and use plain properties where available
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE <=9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p * Math.PI ) / 2;
+ }
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+});
diff --git a/bower_components/jquery/src/effects/animatedSelector.js b/bower_components/jquery/src/effects/animatedSelector.js
new file mode 100644
index 0000000..bc5a3d6
--- /dev/null
+++ b/bower_components/jquery/src/effects/animatedSelector.js
@@ -0,0 +1,13 @@
+define([
+ "../core",
+ "../selector",
+ "../effects"
+], function( jQuery ) {
+
+jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+};
+
+});
diff --git a/bower_components/jquery/src/effects/support.js b/bower_components/jquery/src/effects/support.js
new file mode 100644
index 0000000..3ef7261
--- /dev/null
+++ b/bower_components/jquery/src/effects/support.js
@@ -0,0 +1,55 @@
+define([
+ "../var/strundefined",
+ "../var/support"
+], function( strundefined, support ) {
+
+(function() {
+ var shrinkWrapBlocksVal;
+
+ support.shrinkWrapBlocks = function() {
+ if ( shrinkWrapBlocksVal != null ) {
+ return shrinkWrapBlocksVal;
+ }
+
+ // Will be changed later if needed.
+ shrinkWrapBlocksVal = false;
+
+ // Minified: var b,c,d
+ var div, body, container;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+ // Test fired too early or in an unsupported environment, exit.
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ // Support: IE6
+ // Check if elements with layout shrink-wrap their children
+ if ( typeof div.style.zoom !== strundefined ) {
+ // Reset CSS: box-sizing; display; margin; border
+ div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+ "box-sizing:content-box;display:block;margin:0;border:0;" +
+ "padding:1px;width:1px;zoom:1";
+ div.appendChild( document.createElement( "div" ) ).style.width = "5px";
+ shrinkWrapBlocksVal = div.offsetWidth !== 3;
+ }
+
+ body.removeChild( container );
+
+ return shrinkWrapBlocksVal;
+ };
+
+})();
+
+return support;
+
+});
diff --git a/bower_components/jquery/src/event.js b/bower_components/jquery/src/event.js
new file mode 100644
index 0000000..16ca030
--- /dev/null
+++ b/bower_components/jquery/src/event.js
@@ -0,0 +1,1037 @@
+define([
+ "./core",
+ "./var/strundefined",
+ "./var/rnotwhite",
+ "./var/hasOwn",
+ "./var/slice",
+ "./event/support",
+
+ "./core/init",
+ "./data/accepts",
+ "./selector"
+], function( jQuery, strundefined, rnotwhite, hasOwn, slice, support ) {
+
+var rformElems = /^(?:input|select|textarea)$/i,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+ var tmp, events, t, handleObjIn,
+ special, eventHandle, handleObj,
+ handlers, type, namespaces, origType,
+ elemData = jQuery._data( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+ var j, handleObj, tmp,
+ origCount, t, events,
+ special, handlers, type,
+ namespaces, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery._removeData( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ var handle, ontype, cur,
+ bubbleType, special, tmp, i,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === false ) {
+ event.preventDefault();
+ }
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+ jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ try {
+ elem[ type ]();
+ } catch ( e ) {
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
+ }
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, ret, handleObj, matched, j,
+ handlerQueue = [],
+ args = slice.call( arguments ),
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var sel, handleObj, matches, i,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG <use> instance trees (#13180)
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+ /* jshint eqeqeq: false */
+ for ( ; cur != this; cur = cur.parentNode || this ) {
+ /* jshint eqeqeq: true */
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matches[ sel ] === undefined ) {
+ matches[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matches[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, handlers: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+ }
+
+ return handlerQueue;
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop, copy,
+ type = event.type,
+ originalEvent = event,
+ fixHook = this.fixHooks[ type ];
+
+ if ( !fixHook ) {
+ this.fixHooks[ type ] = fixHook =
+ rmouseEvent.test( type ) ? this.mouseHooks :
+ rkeyEvent.test( type ) ? this.keyHooks :
+ {};
+ }
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = new jQuery.Event( originalEvent );
+
+ i = copy.length;
+ while ( i-- ) {
+ prop = copy[ i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Support: IE<9
+ // Fix target property (#1925)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Support: Chrome 23+, Safari?
+ // Target should not be a text node (#504, #13143)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // Support: IE<9
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
+ event.metaKey = !!event.metaKey;
+
+ return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var body, eventDoc, doc,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ special: {
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ focus: {
+ // Fire native event if possible so blur/focus sequence is correct
+ trigger: function() {
+ if ( this !== safeActiveElement() && this.focus ) {
+ try {
+ this.focus();
+ return false;
+ } catch ( e ) {
+ // Support: IE<9
+ // If we error on focus to hidden element (#1486, #12518),
+ // let .trigger() run the handlers
+ }
+ }
+ },
+ delegateType: "focusin"
+ },
+ blur: {
+ trigger: function() {
+ if ( this === safeActiveElement() && this.blur ) {
+ this.blur();
+ return false;
+ }
+ },
+ delegateType: "focusout"
+ },
+ click: {
+ // For checkbox, fire native event so checked state will be right
+ trigger: function() {
+ if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+ this.click();
+ return false;
+ }
+ },
+
+ // For cross-browser consistency, don't fire native .click() on links
+ _default: function( event ) {
+ return jQuery.nodeName( event.target, "a" );
+ }
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Support: Firefox 20+
+ // Firefox doesn't alert if the returnValue field is not set.
+ if ( event.result !== undefined && event.originalEvent ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ var name = "on" + type;
+
+ if ( elem.detachEvent ) {
+
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
+ if ( typeof elem[ name ] === strundefined ) {
+ elem[ name ] = null;
+ }
+
+ elem.detachEvent( name, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = src.defaultPrevented ||
+ src.defaultPrevented === undefined &&
+ // Support: IE < 9, Android < 4.0
+ src.returnValue === false ?
+ returnTrue :
+ returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+ if ( !e ) {
+ return;
+ }
+
+ // If preventDefault exists, run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // Support: IE
+ // Otherwise set the returnValue property of the original event to false
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+ if ( !e ) {
+ return;
+ }
+ // If stopPropagation exists, run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+
+ // Support: IE
+ // Set the cancelBubble property of the original event to true
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ var e = this.originalEvent;
+
+ this.isImmediatePropagationStopped = returnTrue;
+
+ if ( e && e.stopImmediatePropagation ) {
+ e.stopImmediatePropagation();
+ }
+
+ this.stopPropagation();
+ }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout",
+ pointerenter: "pointerover",
+ pointerleave: "pointerout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// IE submit delegation
+if ( !support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !jQuery._data( form, "submitBubbles" ) ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ jQuery._data( form, "submitBubbles", true );
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
+
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
+ }
+ };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !support.changeBubbles ) {
+
+ jQuery.event.special.change = {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ }
+ // Allow triggered, simulated change events (#11500)
+ jQuery.event.simulate( "change", this, event, true );
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
+
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ jQuery._data( elem, "changeBubbles", true );
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
+ },
+
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return !rformElems.test( this.nodeName );
+ }
+ };
+}
+
+// Create "bubbling" focus and blur events
+if ( !support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler on the document while someone wants focusin/focusout
+ var handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ var doc = this.ownerDocument || this,
+ attaches = jQuery._data( doc, fix );
+
+ if ( !attaches ) {
+ doc.addEventListener( orig, handler, true );
+ }
+ jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this,
+ attaches = jQuery._data( doc, fix ) - 1;
+
+ if ( !attaches ) {
+ doc.removeEventListener( orig, handler, true );
+ jQuery._removeData( doc, fix );
+ } else {
+ jQuery._data( doc, fix, attaches );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var type, origFn;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[0];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/event/alias.js b/bower_components/jquery/src/event/alias.js
new file mode 100644
index 0000000..7e79175
--- /dev/null
+++ b/bower_components/jquery/src/event/alias.js
@@ -0,0 +1,39 @@
+define([
+ "../core",
+ "../event"
+], function( jQuery ) {
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+});
+
+jQuery.fn.extend({
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ }
+});
+
+});
diff --git a/bower_components/jquery/src/event/support.js b/bower_components/jquery/src/event/support.js
new file mode 100644
index 0000000..caac517
--- /dev/null
+++ b/bower_components/jquery/src/event/support.js
@@ -0,0 +1,26 @@
+define([
+ "../var/support"
+], function( support ) {
+
+(function() {
+ var i, eventName,
+ div = document.createElement( "div" );
+
+ // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event)
+ for ( i in { submit: true, change: true, focusin: true }) {
+ eventName = "on" + i;
+
+ if ( !(support[ i + "Bubbles" ] = eventName in window) ) {
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+ div.setAttribute( eventName, "t" );
+ support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false;
+ }
+ }
+
+ // Null elements to avoid leaks in IE.
+ div = null;
+})();
+
+return support;
+
+});
diff --git a/bower_components/jquery/src/exports/amd.js b/bower_components/jquery/src/exports/amd.js
new file mode 100644
index 0000000..9a9846f
--- /dev/null
+++ b/bower_components/jquery/src/exports/amd.js
@@ -0,0 +1,24 @@
+define([
+ "../core"
+], function( jQuery ) {
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function() {
+ return jQuery;
+ });
+}
+
+});
diff --git a/bower_components/jquery/src/exports/global.js b/bower_components/jquery/src/exports/global.js
new file mode 100644
index 0000000..8eee5bb
--- /dev/null
+++ b/bower_components/jquery/src/exports/global.js
@@ -0,0 +1,32 @@
+define([
+ "../core",
+ "../var/strundefined"
+], function( jQuery, strundefined ) {
+
+var
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in
+// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === strundefined ) {
+ window.jQuery = window.$ = jQuery;
+}
+
+});
diff --git a/bower_components/jquery/src/intro.js b/bower_components/jquery/src/intro.js
new file mode 100644
index 0000000..f7dd78d
--- /dev/null
+++ b/bower_components/jquery/src/intro.js
@@ -0,0 +1,44 @@
+/*!
+ * jQuery JavaScript Library v@VERSION
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: @DATE
+ */
+
+(function( global, factory ) {
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+ // For CommonJS and CommonJS-like environments where a proper window is present,
+ // execute the factory and get jQuery
+ // For environments that do not inherently posses a window with a document
+ // (such as Node.js), expose a jQuery-making factory as module.exports
+ // This accentuates the need for the creation of a real window
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//"use strict";
diff --git a/bower_components/jquery/src/jquery.js b/bower_components/jquery/src/jquery.js
new file mode 100644
index 0000000..ac5ea9f
--- /dev/null
+++ b/bower_components/jquery/src/jquery.js
@@ -0,0 +1,37 @@
+define([
+ "./core",
+ "./selector",
+ "./traversing",
+ "./callbacks",
+ "./deferred",
+ "./core/ready",
+ "./support",
+ "./data",
+ "./queue",
+ "./queue/delay",
+ "./attributes",
+ "./event",
+ "./event/alias",
+ "./manipulation",
+ "./manipulation/_evalUrl",
+ "./wrap",
+ "./css",
+ "./css/hiddenVisibleSelectors",
+ "./serialize",
+ "./ajax",
+ "./ajax/xhr",
+ "./ajax/script",
+ "./ajax/jsonp",
+ "./ajax/load",
+ "./effects",
+ "./effects/animatedSelector",
+ "./offset",
+ "./dimensions",
+ "./deprecated",
+ "./exports/amd",
+ "./exports/global"
+], function( jQuery ) {
+
+return jQuery;
+
+});
diff --git a/bower_components/jquery/src/manipulation.js b/bower_components/jquery/src/manipulation.js
new file mode 100644
index 0000000..ee0baeb
--- /dev/null
+++ b/bower_components/jquery/src/manipulation.js
@@ -0,0 +1,744 @@
+define([
+ "./core",
+ "./var/strundefined",
+ "./var/concat",
+ "./var/push",
+ "./var/deletedIds",
+ "./core/access",
+ "./manipulation/var/rcheckableType",
+ "./manipulation/support",
+
+ "./core/init",
+ "./data/accepts",
+ "./traversing",
+ "./selector",
+ "./event"
+], function( jQuery, strundefined, concat, push, deletedIds, access, rcheckableType, support ) {
+
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ rtagName = /<([\w:]+)/,
+ rtbody = /<tbody/i,
+ rhtml = /<|&#?\w+;/,
+ rnoInnerhtml = /<(?:script|style|link)/i,
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /^$|\/(?:java|ecma)script/i,
+ rscriptTypeMasked = /^true\/(.*)/,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+ // We have to close these tags to support XHTML (#13200)
+ wrapMap = {
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
+ area: [ 1, "<map>", "</map>" ],
+ param: [ 1, "<object>", "</object>" ],
+ thead: [ 1, "<table>", "</table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+ // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+ // unless wrapped in a div with non-breaking characters in front of it.
+ _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
+ },
+ safeFragment = createSafeFragment( document ),
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+function getAll( context, tag ) {
+ var elems, elem,
+ i = 0,
+ found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) :
+ typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) :
+ undefined;
+
+ if ( !found ) {
+ for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
+ if ( !tag || jQuery.nodeName( elem, tag ) ) {
+ found.push( elem );
+ } else {
+ jQuery.merge( found, getAll( elem, tag ) );
+ }
+ }
+ }
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], found ) :
+ found;
+}
+
+// Used in buildFragment, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( rcheckableType.test( elem.type ) ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+
+// Support: IE<8
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+ return jQuery.nodeName( elem, "table" ) &&
+ jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
+
+ elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+ elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ var match = rscriptTypeMasked.exec( elem.type );
+ if ( match ) {
+ elem.type = match[1];
+ } else {
+ elem.removeAttribute("type");
+ }
+ return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var elem,
+ i = 0;
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
+ }
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function fixCloneNodeIssues( src, dest ) {
+ var nodeName, e, data;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 copies events bound via attachEvent when using cloneNode.
+ if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
+ data = jQuery._data( dest );
+
+ for ( e in data.events ) {
+ jQuery.removeEvent( dest, e, data.handle );
+ }
+
+ // Event data gets referenced instead of copied if the expando gets copied too
+ dest.removeAttribute( jQuery.expando );
+ }
+
+ // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
+ if ( nodeName === "script" && dest.text !== src.text ) {
+ disableScript( dest ).text = src.text;
+ restoreScript( dest );
+
+ // IE6-10 improperly clones children of object elements using classid.
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
+ } else if ( nodeName === "object" ) {
+ if ( dest.parentNode ) {
+ dest.outerHTML = src.outerHTML;
+ }
+
+ // This path appears unavoidable for IE9. When cloning an object
+ // element in IE9, the outerHTML strategy above is not sufficient.
+ // If the src has innerHTML and the destination does not,
+ // copy the src.innerHTML into the dest.innerHTML. #10324
+ if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
+ dest.innerHTML = src.innerHTML;
+ }
+
+ } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+
+ dest.defaultChecked = dest.checked = src.checked;
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.defaultSelected = dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var destElements, node, clone, i, srcElements,
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+ clone = elem.cloneNode( true );
+
+ // IE<=8 does not properly clone detached, unknown element nodes
+ } else {
+ fragmentDiv.innerHTML = elem.outerHTML;
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+ }
+
+ if ( (!support.noCloneEvent || !support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ // Fix all IE cloning issues
+ for ( i = 0; (node = srcElements[i]) != null; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ fixCloneNodeIssues( node, destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0; (node = srcElements[i]) != null; i++ ) {
+ cloneCopyEvent( node, destElements[i] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ destElements = srcElements = node = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ buildFragment: function( elems, context, scripts, selection ) {
+ var j, elem, contains,
+ tmp, tag, tbody, wrap,
+ l = elems.length,
+
+ // Ensure a safe fragment
+ safe = createSafeFragment( context ),
+
+ nodes = [],
+ i = 0;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || safe.appendChild( context.createElement("div") );
+
+ // Deserialize a standard representation
+ tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+
+ tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
+
+ // Descend through wrappers to the right content
+ j = wrap[0];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Manually add leading whitespace removed by IE
+ if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
+ }
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( !support.tbody ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ elem = tag === "table" && !rtbody.test( elem ) ?
+ tmp.firstChild :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] === "<table>" && !rtbody.test( elem ) ?
+ tmp :
+ 0;
+
+ j = elem && elem.childNodes.length;
+ while ( j-- ) {
+ if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+ elem.removeChild( tbody );
+ }
+ }
+ }
+
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Fix #12392 for WebKit and IE > 9
+ tmp.textContent = "";
+
+ // Fix #12392 for oldIE
+ while ( tmp.firstChild ) {
+ tmp.removeChild( tmp.firstChild );
+ }
+
+ // Remember the top-level container for proper cleanup
+ tmp = safe.lastChild;
+ }
+ }
+ }
+
+ // Fix #11356: Clear elements from fragment
+ if ( tmp ) {
+ safe.removeChild( tmp );
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !support.appendChecked ) {
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+ }
+
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( safe.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ tmp = null;
+
+ return safe;
+ },
+
+ cleanData: function( elems, /* internal */ acceptData ) {
+ var elem, type, id, data,
+ i = 0,
+ internalKey = jQuery.expando,
+ cache = jQuery.cache,
+ deleteExpando = support.deleteExpando,
+ special = jQuery.event.special;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( acceptData || jQuery.acceptData( elem ) ) {
+
+ id = elem[ internalKey ];
+ data = id && cache[ id ];
+
+ if ( data ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Remove cache only if it was not already removed by jQuery.event.remove
+ if ( cache[ id ] ) {
+
+ delete cache[ id ];
+
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( deleteExpando ) {
+ delete elem[ internalKey ];
+
+ } else if ( typeof elem.removeAttribute !== strundefined ) {
+ elem.removeAttribute( internalKey );
+
+ } else {
+ elem[ internalKey ] = null;
+ }
+
+ deletedIds.push( id );
+ }
+ }
+ }
+ }
+ }
+});
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ });
+ },
+
+ after: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ });
+ },
+
+ remove: function( selector, keepData /* Internal Use Only */ ) {
+ var elem,
+ elems = selector ? jQuery.filter( selector, this ) : this,
+ i = 0;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem ) );
+ }
+
+ if ( elem.parentNode ) {
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+ setGlobalEval( getAll( elem, "script" ) );
+ }
+ elem.parentNode.removeChild( elem );
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+
+ // If this is a select, ensure that it displays empty (#12336)
+ // Support: IE<9
+ if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
+ elem.options.length = 0;
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map(function() {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return access( this, function( value ) {
+ var elem = this[ 0 ] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ undefined;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( support.htmlSerialize || !rnoshimcache.test( value ) ) &&
+ ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var arg = arguments[ 0 ];
+
+ // Make the changes, replacing each context element with the new content
+ this.domManip( arguments, function( elem ) {
+ arg = this.parentNode;
+
+ jQuery.cleanData( getAll( this ) );
+
+ if ( arg ) {
+ arg.replaceChild( elem, this );
+ }
+ });
+
+ // Force removal if there was no new content (e.g., from empty arguments)
+ return arg && (arg.length || arg.nodeType) ? this : this.remove();
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, callback ) {
+
+ // Flatten any nested arrays
+ args = concat.apply( [], args );
+
+ var first, node, hasScripts,
+ scripts, doc, fragment,
+ i = 0,
+ l = this.length,
+ set = this,
+ iNoClone = l - 1,
+ value = args[0],
+ isFunction = jQuery.isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( isFunction ||
+ ( l > 1 && typeof value === "string" &&
+ !support.checkClone && rchecked.test( value ) ) ) {
+ return this.each(function( index ) {
+ var self = set.eq( index );
+ if ( isFunction ) {
+ args[0] = value.call( this, index, self.html() );
+ }
+ self.domManip( args, callback );
+ });
+ }
+
+ if ( l ) {
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( this[i], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+ // Optional AJAX dependency, but won't run scripts if not present
+ if ( jQuery._evalUrl ) {
+ jQuery._evalUrl( node.src );
+ }
+ } else {
+ jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
+ }
+ }
+ }
+ }
+
+ // Fix #11809: Avoid leaking memory
+ fragment = first = null;
+ }
+ }
+
+ return this;
+ }
+});
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ i = 0,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone(true);
+ jQuery( insert[i] )[ original ]( elems );
+
+ // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+ push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/manipulation/_evalUrl.js b/bower_components/jquery/src/manipulation/_evalUrl.js
new file mode 100644
index 0000000..6704749
--- /dev/null
+++ b/bower_components/jquery/src/manipulation/_evalUrl.js
@@ -0,0 +1,18 @@
+define([
+ "../ajax"
+], function( jQuery ) {
+
+jQuery._evalUrl = function( url ) {
+ return jQuery.ajax({
+ url: url,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+};
+
+return jQuery._evalUrl;
+
+});
diff --git a/bower_components/jquery/src/manipulation/support.js b/bower_components/jquery/src/manipulation/support.js
new file mode 100644
index 0000000..2567d7e
--- /dev/null
+++ b/bower_components/jquery/src/manipulation/support.js
@@ -0,0 +1,76 @@
+define([
+ "../var/support"
+], function( support ) {
+
+(function() {
+ // Minified: var a,b,c
+ var input = document.createElement( "input" ),
+ div = document.createElement( "div" ),
+ fragment = document.createDocumentFragment();
+
+ // Setup
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+
+ // IE strips leading whitespace when .innerHTML is used
+ support.leadingWhitespace = div.firstChild.nodeType === 3;
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ support.tbody = !div.getElementsByTagName( "tbody" ).length;
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ support.html5Clone =
+ document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>";
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ input.type = "checkbox";
+ input.checked = true;
+ fragment.appendChild( input );
+ support.appendChecked = input.checked;
+
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ // Support: IE6-IE11+
+ div.innerHTML = "<textarea>x</textarea>";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ fragment.appendChild( div );
+ div.innerHTML = "<input type='radio' checked='checked' name='t'/>";
+
+ // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
+ // old WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<9
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+ support.noCloneEvent = true;
+ if ( div.attachEvent ) {
+ div.attachEvent( "onclick", function() {
+ support.noCloneEvent = false;
+ });
+
+ div.cloneNode( true ).click();
+ }
+
+ // Execute the test only if not already executed in another module.
+ if (support.deleteExpando == null) {
+ // Support: IE<9
+ support.deleteExpando = true;
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+ }
+})();
+
+return support;
+
+});
diff --git a/bower_components/jquery/src/manipulation/var/rcheckableType.js b/bower_components/jquery/src/manipulation/var/rcheckableType.js
new file mode 100644
index 0000000..c27a15d
--- /dev/null
+++ b/bower_components/jquery/src/manipulation/var/rcheckableType.js
@@ -0,0 +1,3 @@
+define(function() {
+ return (/^(?:checkbox|radio)$/i);
+});
diff --git a/bower_components/jquery/src/offset.js b/bower_components/jquery/src/offset.js
new file mode 100644
index 0000000..42d07eb
--- /dev/null
+++ b/bower_components/jquery/src/offset.js
@@ -0,0 +1,211 @@
+define([
+ "./core",
+ "./var/strundefined",
+ "./core/access",
+ "./css/var/rnumnonpx",
+ "./css/curCSS",
+ "./css/addGetHookIf",
+ "./css/support",
+
+ "./core/init",
+ "./css",
+ "./selector" // contains
+], function( jQuery, strundefined, access, rnumnonpx, curCSS, addGetHookIf, support ) {
+
+// BuildExclude
+curCSS = curCSS.curCSS;
+
+var docElem = window.document.documentElement;
+
+/**
+ * Gets a window from an element
+ */
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+
+jQuery.offset = {
+ setOffset: function( elem, options, i ) {
+ var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+ position = jQuery.css( elem, "position" ),
+ curElem = jQuery( elem ),
+ props = {};
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ curOffset = curElem.offset();
+ curCSSTop = jQuery.css( elem, "top" );
+ curCSSLeft = jQuery.css( elem, "left" );
+ calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+ jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+jQuery.fn.extend({
+ offset: function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var docElem, win,
+ box = { top: 0, left: 0 },
+ elem = this[ 0 ],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return;
+ }
+
+ docElem = doc.documentElement;
+
+ // Make sure it's not a disconnected DOM node
+ if ( !jQuery.contains( docElem, elem ) ) {
+ return box;
+ }
+
+ // If we don't have gBCR, just use 0,0 rather than error
+ // BlackBerry 5, iOS 3 (original iPhone)
+ if ( typeof elem.getBoundingClientRect !== strundefined ) {
+ box = elem.getBoundingClientRect();
+ }
+ win = getWindow( doc );
+ return {
+ top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
+ left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
+ };
+ },
+
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset,
+ parentOffset = { top: 0, left: 0 },
+ elem = this[ 0 ];
+
+ // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+ // we assume that getBoundingClientRect is available when computed position is fixed
+ offset = elem.getBoundingClientRect();
+ } else {
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent();
+
+ // Get correct offsets
+ offset = this.offset();
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+ parentOffset = offsetParent.offset();
+ }
+
+ // Add offsetParent borders
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ }
+
+ // Subtract parent offsets and element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || docElem;
+
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent || docElem;
+ });
+ }
+});
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+ var top = /Y/.test( prop );
+
+ jQuery.fn[ method ] = function( val ) {
+ return access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ win.document.documentElement[ method ] :
+ elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// getComputedStyle returns percent when specified for top/left/bottom/right
+// rather than make the css module depend on the offset module, we just check for it here
+jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+ function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ );
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/outro.js b/bower_components/jquery/src/outro.js
new file mode 100644
index 0000000..be4600a
--- /dev/null
+++ b/bower_components/jquery/src/outro.js
@@ -0,0 +1 @@
+}));
diff --git a/bower_components/jquery/src/queue.js b/bower_components/jquery/src/queue.js
new file mode 100644
index 0000000..29e7660
--- /dev/null
+++ b/bower_components/jquery/src/queue.js
@@ -0,0 +1,142 @@
+define([
+ "./core",
+ "./deferred",
+ "./callbacks"
+], function( jQuery ) {
+
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery._removeData( elem, type + "queue" );
+ jQuery._removeData( elem, key );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while ( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/queue/delay.js b/bower_components/jquery/src/queue/delay.js
new file mode 100644
index 0000000..4b4498c
--- /dev/null
+++ b/bower_components/jquery/src/queue/delay.js
@@ -0,0 +1,22 @@
+define([
+ "../core",
+ "../queue",
+ "../effects" // Delay is optional because of this dependency
+], function( jQuery ) {
+
+// Based off of the plugin by Clint Helfers, with permission.
+// http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+};
+
+return jQuery.fn.delay;
+});
diff --git a/bower_components/jquery/src/selector-sizzle.js b/bower_components/jquery/src/selector-sizzle.js
new file mode 100644
index 0000000..7d3926b
--- /dev/null
+++ b/bower_components/jquery/src/selector-sizzle.js
@@ -0,0 +1,14 @@
+define([
+ "./core",
+ "sizzle"
+], function( jQuery, Sizzle ) {
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+});
diff --git a/bower_components/jquery/src/selector.js b/bower_components/jquery/src/selector.js
new file mode 100644
index 0000000..01e9733
--- /dev/null
+++ b/bower_components/jquery/src/selector.js
@@ -0,0 +1 @@
+define([ "./selector-sizzle" ]);
diff --git a/bower_components/jquery/src/serialize.js b/bower_components/jquery/src/serialize.js
new file mode 100644
index 0000000..5b09cb6
--- /dev/null
+++ b/bower_components/jquery/src/serialize.js
@@ -0,0 +1,110 @@
+define([
+ "./core",
+ "./manipulation/var/rcheckableType",
+ "./core/init",
+ "./traversing", // filter
+ "./attributes/prop"
+], function( jQuery, rcheckableType ) {
+
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function() {
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ })
+ .filter(function() {
+ var type = this.type;
+ // Use .is(":disabled") so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !rcheckableType.test( type ) );
+ })
+ .map(function( i, elem ) {
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ) {
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/sizzle/dist/sizzle.js b/bower_components/jquery/src/sizzle/dist/sizzle.js
new file mode 100644
index 0000000..20bc017
--- /dev/null
+++ b/bower_components/jquery/src/sizzle/dist/sizzle.js
@@ -0,0 +1,2044 @@
+/*!
+ * Sizzle CSS Selector Engine v1.10.19
+ * http://sizzlejs.com/
+ *
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-04-18
+ */
+(function( window ) {
+
+var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ tokenize,
+ compile,
+ select,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + -(new Date()),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ strundefined = typeof undefined,
+ MAX_NEGATIVE = 1 << 31,
+
+ // Instance methods
+ hasOwn = ({}).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ push_native = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf if we can't use a native one
+ indexOf = arr.indexOf || function( elem ) {
+ var i = 0,
+ len = this.length;
+ for ( ; i < len; i++ ) {
+ if ( this[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
+ // Operator (capture 2)
+ "*([*^$|!~]?=)" + whitespace +
+ // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+ "*\\]",
+
+ pseudos = ":(" + characterEncoding + ")(?:\\((" +
+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+ // 1. quoted (capture 3; capture 4 or capture 5)
+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+ // 2. simple (capture 6)
+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+ // 3. anything else (capture 2)
+ ".*" +
+ ")\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+ rescape = /'|\\/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+ funescape = function( _, escaped, escapedWhitespace ) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ // Support: Firefox<24
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ high < 0 ?
+ // BMP codepoint
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ };
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ (arr = slice.call( preferredDoc.childNodes )),
+ preferredDoc.childNodes
+ );
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ push_native.apply( target, slice.call(els) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+ // Can't trust NodeList.length
+ while ( (target[j++] = els[i++]) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var match, elem, m, nodeType,
+ // QSA vars
+ i, groups, old, nid, newContext, newSelector;
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+
+ context = context || document;
+ results = results || [];
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( documentIsHTML && !seed ) {
+
+ // Shortcuts
+ if ( (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document (jQuery #6963)
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // QSA path
+ if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+ nid = old = expando;
+ newContext = context;
+ newSelector = nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + toSelector( groups[i] );
+ }
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key + " " ) > Expr.cacheLength ) {
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return (cache[ key + " " ] = value);
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return !!fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // Remove from its parent by default
+ if ( div.parentNode ) {
+ div.parentNode.removeChild( div );
+ }
+ // release memory in IE
+ div = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split("|"),
+ i = attrs.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[i] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
+ ( ~a.sourceIndex || MAX_NEGATIVE );
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( (cur = cur.nextSibling) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+ return context && typeof context.getElementsByTagName !== strundefined && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var hasCompare,
+ doc = node ? node.ownerDocument || node : preferredDoc,
+ parent = doc.defaultView;
+
+ // If no document and documentElement is available, return
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Set our document
+ document = doc;
+ docElem = doc.documentElement;
+
+ // Support tests
+ documentIsHTML = !isXML( doc );
+
+ // Support: IE>8
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+ // IE6-8 do not support the defaultView property so parent will be undefined
+ if ( parent && parent !== parent.top ) {
+ // IE11 does not have attachEvent, so all must suffer
+ if ( parent.addEventListener ) {
+ parent.addEventListener( "unload", function() {
+ setDocument();
+ }, false );
+ } else if ( parent.attachEvent ) {
+ parent.attachEvent( "onunload", function() {
+ setDocument();
+ });
+ }
+ }
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
+ support.attributes = assert(function( div ) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function( div ) {
+ div.appendChild( doc.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Check if getElementsByClassName can be trusted
+ support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
+ div.innerHTML = "<div class='a'></div><div class='a i'></div>";
+
+ // Support: Safari<4
+ // Catch class over-caching
+ div.firstChild.className = "i";
+ // Support: Opera<10
+ // Catch gEBCN failure to find non-leading classes
+ return div.getElementsByClassName("i").length === 2;
+ });
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert(function( div ) {
+ docElem.appendChild( div ).id = expando;
+ return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+ });
+
+ // ID find and filter
+ if ( support.getById ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [ m ] : [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ // Support: IE6/7
+ // getElementById is not reliable as a find shortcut
+ delete Expr.find["ID"];
+
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== strundefined ) {
+ return context.getElementsByTagName( tag );
+ }
+ } :
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See http://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
+
+ // Support: IE8, Opera 11-12.16
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ // The test attribute must be unknown in Opera but "safe" for WinRT
+ // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if ( div.querySelectorAll("[msallowclip^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function( div ) {
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = doc.createElement("input");
+ input.setAttribute( "type", "hidden" );
+ div.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if ( div.querySelectorAll("[name=d]").length ) {
+ rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
+ docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector) )) ) {
+
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( div, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ });
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+ // Element contains another
+ // Purposefully does not implement inclusive descendent
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test( docElem.contains ) ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ));
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if ( compare ) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+ a.compareDocumentPosition( b ) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if ( compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+ // Choose the first element that is related to our preferred document
+ if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+ return -1;
+ }
+ if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function( a, b ) {
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Parentless nodes are either documents or disconnected
+ if ( !aup || !bup ) {
+ return a === doc ? -1 :
+ b === doc ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( (cur = cur.parentNode) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( (cur = cur.parentNode) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[i] === bp[i] ) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[i], bp[i] ) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+ // Set document vars if needed
+ if ( ( context.ownerDocument || context ) !== document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val !== undefined ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+ // If no nodeType, this is expected to be an array
+ while ( (node = elem[i++]) ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (jQuery #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
+ // nth-* requires argument
+ if ( !match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[6] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[3] ) {
+ match[2] = match[4] || match[5] || "";
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ match[0] = match[0].slice( 0, excess );
+ match[2] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() { return true; } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, what, argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, context, xml ) {
+ var cache, outerCache, node, diff, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( (node = node[ dir ]) ) {
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+ // Seek `elem` from a previously-cached index
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
+ cache = outerCache[ type ] || [];
+ nodeIndex = cache[0] === dirruns && cache[1];
+ diff = cache[0] === dirruns && cache[2];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ // Use previously-cached element index if available
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+ diff = cache[1];
+
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ } else {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf.call( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+ // lang value must be a valid identifier
+ if ( !ridentifier.test(lang || "") ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( (elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+ return false;
+ };
+ }),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeType < 6 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( (tokens = []) );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace( rtrim, " " )
+ });
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ type: type,
+ matches: match
+ });
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[i].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var oldCache, outerCache,
+ newCache = [ dirruns, doneName ];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
+ if ( (oldCache = outerCache[ dir ]) &&
+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return (newCache[ 2 ] = oldCache[ 2 ]);
+ } else {
+ // Reuse newcache so results back-propagate to previous elements
+ outerCache[ dir ] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf.call( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, outermost ) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+ len = elems.length;
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+ for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( (matcher = setMatchers[j++]) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !match ) {
+ match = tokenize( selector );
+ }
+ i = match.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( match[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+
+ // Save selector and tokenization
+ cached.selector = selector;
+ }
+ return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ * selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ * selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ compiled = typeof selector === "function" && selector,
+ match = !seed && tokenize( (selector = compiled.selector || selector) );
+
+ results = results || [];
+
+ // Try to minimize operations if there is no seed and only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ support.getById && context.nodeType === 9 && documentIsHTML &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+ if ( !context ) {
+ return results;
+
+ // Precompiled matchers will still verify ancestry, so step up a level
+ } else if ( compiled ) {
+ context = context.parentNode;
+ }
+
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( runescape, funescape ),
+ rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function if one is not provided
+ // Provide `match` to avoid retokenization if we modified the selector above
+ ( compiled || compile( selector, match ) )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ rsibling.test( selector ) && testContext( context.parentNode ) || context
+ );
+ return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome<14
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+ // Should return 1, but returns 4 (following)
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+ div.innerHTML = "<a href='#'></a>";
+ return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+ div.innerHTML = "<input/>";
+ div.firstChild.setAttribute( "value", "" );
+ return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+ addHandle( "value", function( elem, name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+ return div.getAttribute("disabled") == null;
+}) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return elem[ name ] === true ? name.toLowerCase() :
+ (val = elem.getAttributeNode( name )) && val.specified ?
+ val.value :
+ null;
+ }
+ });
+}
+
+// EXPOSE
+if ( typeof define === "function" && define.amd ) {
+ define(function() { return Sizzle; });
+// Sizzle requires that there be a global window in Common-JS like environments
+} else if ( typeof module !== "undefined" && module.exports ) {
+ module.exports = Sizzle;
+} else {
+ window.Sizzle = Sizzle;
+}
+// EXPOSE
+
+})( window );
diff --git a/bower_components/jquery/src/support.js b/bower_components/jquery/src/support.js
new file mode 100644
index 0000000..4728be8
--- /dev/null
+++ b/bower_components/jquery/src/support.js
@@ -0,0 +1,58 @@
+define([
+ "./core",
+ "./var/strundefined",
+ "./var/support",
+ "./core/init", // Needed for hasOwn support test
+ // This is listed as a dependency for build order, but it's still optional in builds
+ "./core/ready"
+], function( jQuery, strundefined, support ) {
+
+// Support: IE<9
+// Iteration over object's inherited properties before its own
+var i;
+for ( i in jQuery( support ) ) {
+ break;
+}
+support.ownLast = i !== "0";
+
+// Note: most support tests are defined in their respective modules.
+// false until the test is run
+support.inlineBlockNeedsLayout = false;
+
+// Execute ASAP in case we need to set body.style.zoom
+jQuery(function() {
+ // Minified: var a,b,c,d
+ var val, div, body, container;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ if ( typeof div.style.zoom !== strundefined ) {
+ // Support: IE<8
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
+
+ support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
+ if ( val ) {
+ // Prevent IE 6 from affecting layout for positioned elements #11048
+ // Prevent IE from shrinking the body in IE 7 mode #12869
+ // Support: IE<8
+ body.style.zoom = 1;
+ }
+ }
+
+ body.removeChild( container );
+});
+
+});
diff --git a/bower_components/jquery/src/traversing.js b/bower_components/jquery/src/traversing.js
new file mode 100644
index 0000000..ee36769
--- /dev/null
+++ b/bower_components/jquery/src/traversing.js
@@ -0,0 +1,200 @@
+define([
+ "./core",
+ "./traversing/var/rneedsContext",
+ "./core/init",
+ "./traversing/findFilter",
+ "./selector"
+], function( jQuery, rneedsContext ) {
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.extend({
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+jQuery.fn.extend({
+ has: function( target ) {
+ var i,
+ targets = jQuery( target, this ),
+ len = targets.length;
+
+ return this.filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ matched = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && (pos ?
+ pos.index(cur) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector(cur, selectors)) ) {
+
+ matched.push( cur );
+ break;
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ return this.pushStack(
+ jQuery.unique(
+ jQuery.merge( this.get(), jQuery( selector, context ) )
+ )
+ );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
+ }
+});
+
+function sibling( cur, dir ) {
+ do {
+ cur = cur[ dir ];
+ } while ( cur && cur.nodeType !== 1 );
+
+ return cur;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ if ( this.length > 1 ) {
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ ret = jQuery.unique( ret );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+return jQuery;
+});
diff --git a/bower_components/jquery/src/traversing/findFilter.js b/bower_components/jquery/src/traversing/findFilter.js
new file mode 100644
index 0000000..e295045
--- /dev/null
+++ b/bower_components/jquery/src/traversing/findFilter.js
@@ -0,0 +1,100 @@
+define([
+ "../core",
+ "../var/indexOf",
+ "./var/rneedsContext",
+ "../selector"
+], function( jQuery, indexOf, rneedsContext ) {
+
+var risSimple = /^.[^:#\[\.,]*$/;
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ /* jshint -W018 */
+ return !!qualifier.call( elem, i, elem ) !== not;
+ });
+
+ }
+
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ });
+
+ }
+
+ if ( typeof qualifier === "string" ) {
+ if ( risSimple.test( qualifier ) ) {
+ return jQuery.filter( qualifier, elements, not );
+ }
+
+ qualifier = jQuery.filter( qualifier, elements );
+ }
+
+ return jQuery.grep( elements, function( elem ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
+ });
+}
+
+jQuery.filter = function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 && elem.nodeType === 1 ?
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ }));
+};
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var i,
+ ret = [],
+ self = this,
+ len = self.length;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ }) );
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
+ return ret;
+ },
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], false) );
+ },
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], true) );
+ },
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ }
+});
+
+});
diff --git a/bower_components/jquery/src/traversing/var/rneedsContext.js b/bower_components/jquery/src/traversing/var/rneedsContext.js
new file mode 100644
index 0000000..3d6ae40
--- /dev/null
+++ b/bower_components/jquery/src/traversing/var/rneedsContext.js
@@ -0,0 +1,6 @@
+define([
+ "../../core",
+ "../../selector"
+], function( jQuery ) {
+ return jQuery.expr.match.needsContext;
+});
diff --git a/bower_components/jquery/src/var/class2type.js b/bower_components/jquery/src/var/class2type.js
new file mode 100644
index 0000000..e674c3b
--- /dev/null
+++ b/bower_components/jquery/src/var/class2type.js
@@ -0,0 +1,4 @@
+define(function() {
+ // [[Class]] -> type pairs
+ return {};
+});
diff --git a/bower_components/jquery/src/var/concat.js b/bower_components/jquery/src/var/concat.js
new file mode 100644
index 0000000..8606ea3
--- /dev/null
+++ b/bower_components/jquery/src/var/concat.js
@@ -0,0 +1,5 @@
+define([
+ "./deletedIds"
+], function( deletedIds ) {
+ return deletedIds.concat;
+});
diff --git a/bower_components/jquery/src/var/deletedIds.js b/bower_components/jquery/src/var/deletedIds.js
new file mode 100644
index 0000000..b18fc9c
--- /dev/null
+++ b/bower_components/jquery/src/var/deletedIds.js
@@ -0,0 +1,3 @@
+define(function() {
+ return [];
+});
diff --git a/bower_components/jquery/src/var/hasOwn.js b/bower_components/jquery/src/var/hasOwn.js
new file mode 100644
index 0000000..32c002a
--- /dev/null
+++ b/bower_components/jquery/src/var/hasOwn.js
@@ -0,0 +1,5 @@
+define([
+ "./class2type"
+], function( class2type ) {
+ return class2type.hasOwnProperty;
+});
diff --git a/bower_components/jquery/src/var/indexOf.js b/bower_components/jquery/src/var/indexOf.js
new file mode 100644
index 0000000..fafddd4
--- /dev/null
+++ b/bower_components/jquery/src/var/indexOf.js
@@ -0,0 +1,5 @@
+define([
+ "./deletedIds"
+], function( deletedIds ) {
+ return deletedIds.indexOf;
+});
diff --git a/bower_components/jquery/src/var/pnum.js b/bower_components/jquery/src/var/pnum.js
new file mode 100644
index 0000000..4070447
--- /dev/null
+++ b/bower_components/jquery/src/var/pnum.js
@@ -0,0 +1,3 @@
+define(function() {
+ return (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
+});
diff --git a/bower_components/jquery/src/var/push.js b/bower_components/jquery/src/var/push.js
new file mode 100644
index 0000000..cc1e105
--- /dev/null
+++ b/bower_components/jquery/src/var/push.js
@@ -0,0 +1,5 @@
+define([
+ "./deletedIds"
+], function( deletedIds ) {
+ return deletedIds.push;
+});
diff --git a/bower_components/jquery/src/var/rnotwhite.js b/bower_components/jquery/src/var/rnotwhite.js
new file mode 100644
index 0000000..7c69bec
--- /dev/null
+++ b/bower_components/jquery/src/var/rnotwhite.js
@@ -0,0 +1,3 @@
+define(function() {
+ return (/\S+/g);
+});
diff --git a/bower_components/jquery/src/var/slice.js b/bower_components/jquery/src/var/slice.js
new file mode 100644
index 0000000..d47618a
--- /dev/null
+++ b/bower_components/jquery/src/var/slice.js
@@ -0,0 +1,5 @@
+define([
+ "./deletedIds"
+], function( deletedIds ) {
+ return deletedIds.slice;
+});
diff --git a/bower_components/jquery/src/var/strundefined.js b/bower_components/jquery/src/var/strundefined.js
new file mode 100644
index 0000000..04e16b0
--- /dev/null
+++ b/bower_components/jquery/src/var/strundefined.js
@@ -0,0 +1,3 @@
+define(function() {
+ return typeof undefined;
+});
diff --git a/bower_components/jquery/src/var/support.js b/bower_components/jquery/src/var/support.js
new file mode 100644
index 0000000..b25dbc7
--- /dev/null
+++ b/bower_components/jquery/src/var/support.js
@@ -0,0 +1,4 @@
+define(function() {
+ // All support tests are defined in their respective modules.
+ return {};
+});
diff --git a/bower_components/jquery/src/var/toString.js b/bower_components/jquery/src/var/toString.js
new file mode 100644
index 0000000..ca92d22
--- /dev/null
+++ b/bower_components/jquery/src/var/toString.js
@@ -0,0 +1,5 @@
+define([
+ "./class2type"
+], function( class2type ) {
+ return class2type.toString;
+});
diff --git a/bower_components/jquery/src/wrap.js b/bower_components/jquery/src/wrap.js
new file mode 100644
index 0000000..a3c35d9
--- /dev/null
+++ b/bower_components/jquery/src/wrap.js
@@ -0,0 +1,75 @@
+define([
+ "./core",
+ "./core/init",
+ "./traversing" // parent, contents
+], function( jQuery ) {
+
+jQuery.fn.extend({
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ }
+});
+
+return jQuery;
+});
diff --git a/docs/creating-a-theme.txt b/docs/creating-a-theme.txt
index 40a4566..220a8e7 100644
--- a/docs/creating-a-theme.txt
+++ b/docs/creating-a-theme.txt
@@ -1,6 +1,6 @@
.. title: Creating a Theme
.. slug: creating-a-theme
-.. date: 2012/03/13 12:00
+.. date: 2012-03-13 12:00:00 UTC-03:00
.. tags:
.. link:
.. description:
@@ -107,7 +107,7 @@ The general page layout for the theme is done by the ``base.tmpl`` template, whi
<li>${base.html_translations()}</li>
%endif
</%block>
- % if not hide_sourcelink:
+ % if show_sourcelink:
<li><%block name="sourcelink"></%block></li>
%endif
</ul>
@@ -131,7 +131,7 @@ The general page layout for the theme is done by the ``base.tmpl`` template, whi
</div>
${bootstrap.late_load_js()}
${base.html_social()}
- <script type="text/javascript">jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"100%",maxHeight:"100%",scalePhotos:true});
+ <script>jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"100%",maxHeight:"100%",scalePhotos:true});
$(window).on('hashchange', function(){
if (location.hash && $(location.hash)[0]) {
$('body').animate({scrollTop: $(location.hash).offset().top - $('#navbar').outerHeight(true)*1.2 }, 1);
@@ -193,7 +193,7 @@ Monospace is a two-column-with-footer layout, so let's copy the basics from its
</div>
</div>
${bootstrap.late_load_js()}
- <script type="text/javascript">jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"100%",maxHeight:"100%",scalePhotos:true});</script>
+ <script>jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"100%",maxHeight:"100%",scalePhotos:true});</script>
<%block name="extra_js"></%block>
${body_end}
</body>
diff --git a/docs/extending.txt b/docs/extending.txt
index fb216c5..f8b685a 100644
--- a/docs/extending.txt
+++ b/docs/extending.txt
@@ -1,6 +1,6 @@
.. title: Extending Nikola
.. slug: extending
-.. date: 2012/03/30 23:00
+.. date: 2012-03-30 23:00:00 UTC-03:00
.. tags:
.. link:
.. description:
@@ -8,7 +8,7 @@
Extending Nikola
================
-:Version: 6.4.0
+:Version: 7.0.1
:Author: Roberto Alsina <ralsina@netmanagers.com.ar>
.. class:: alert alert-info pull-right
@@ -369,6 +369,11 @@ RestExtension Plugins
Implement directives for reStructuredText, see ``media.py`` for a simple example.
+MarkdownExtension Plugins
+-------------------------
+
+Implement Markdown extensions, see ``mdx_nikola.py`` for a simple example.
+
SignalHandler Plugins
---------------------
@@ -383,15 +388,17 @@ Currently Nikola emits the following signals:
``sighandlers_loaded``
Right after SignalHandler plugin activation.
``initialized``
- Right after plugin activation.
+ When all tasks are loaded.
``configured``
When all the configuration file is processed. Note that plugins are activated before this is emitted.
+``scanned``
+ After posts are scanned.
``new_post``
When a new post is created, using the ``nikola new_post`` command. The signal
data contains the path of the file, and the metadata file (if there is one).
``deployed``
When the ``nikola deploy`` command is run, and there is at least one new
- entry/post since ``last_deploy``. The signal data is of the form ::
+ entry/post since ``last_deploy``. The signal data is of the form::
{
'last_deploy: # datetime object for the last deployed time,
@@ -436,3 +443,56 @@ Here's the relevant code from the tag plugin.
self.site.config['TAG_PATH'], self.slugify_name(name) + ".xml"] if
_f]
+Template Hooks
+==============
+
+Plugins can use a hook system for adding stuff into templates. In order to use
+it, a plugin must register itself. The following hooks currently exist:
+
+* ``extra_head`` (not equal to the config option!)
+* ``body_end`` (not equal to the config option!)
+* ``page_header``
+* ``menu``
+* ``menu_alt`` (right-side menu in bootstrap, after ``menu`` in base)
+* ``page_footer``
+
+For example, in order to register a script into ``extra_head``:
+
+.. code-block:: python
+
+ # In set_site
+ site.template_hooks['extra_head'].append('<script src="/assets/js/fancyplugin.js">')
+
+There is also another API available. It allows use of dynamically generated
+HTML:
+
+.. code-block:: python
+
+ # In set_site
+ def generate_html_bit(name, ftype='js'):
+ return '<script src="/assets/{t}/{n}.{t}">'.format(n=name, t=ftype)
+
+ site.template_hooks['extra_head'].append(generate_html_bit, False, 'fancyplugin', type='js')
+
+
+The second argument to ``append()`` is used to determine whether the function
+needs access to the current template context and the site. If it it set to
+``True``, the function will also receive ``site`` and ``context`` keyword
+arguments. Example use:
+
+
+.. code-block:: python
+
+ # In set_site
+ def greeting(addr, endswith='', site=None, context=None):
+ if context['lang'] == 'en':
+ greet = u'Hello'
+ elif context['lang'] == 'es':
+ greet = u'¡Hola'
+
+ t = u' BLOG_TITLE = {0}'.format(site.config['BLOG_TITLE'](context['lang']))
+
+ return u'<h3>{greet} {addr}{endswith}</h3>'.format(greet=greet, addr=addr,
+ endswith=endswith) + t
+
+ site.template_hooks['page_header'].append(greeting, True, u'Nikola Tesla', endswith=u'!')
diff --git a/docs/getting-help.txt b/docs/getting-help.txt
index 31edc8d..b36d98c 100644
--- a/docs/getting-help.txt
+++ b/docs/getting-help.txt
@@ -3,7 +3,7 @@
.. date: 1970-01-01 15:00:00
.. description: Get help using Nikola, or contact us.
-:Version: 6.4.0
+:Version: 7.0.1
.. class:: alert alert-info pull-right
diff --git a/docs/internals.txt b/docs/internals.txt
index 06a2747..a025075 100644
--- a/docs/internals.txt
+++ b/docs/internals.txt
@@ -1,6 +1,6 @@
.. title: Nikola Internals
.. slug: internals
-.. date: 2012/03/30 23:00
+.. date: 2012-03-30 23:00:00 UTC-03:00
.. tags:
.. link:
.. description:
diff --git a/docs/man/nikola.1 b/docs/man/nikola.1
index 214a924..0379d29 100644
--- a/docs/man/nikola.1
+++ b/docs/man/nikola.1
@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
-.TH NIKOLA "1" "March 2014" "nikola 6.4.0" "User Commands"
+.TH NIKOLA "1" "June 2014" "nikola 7.0.1" "User Commands"
.SH NAME
-nikola \- manual page for nikola 6.4.0
+nikola \- manual page for nikola 7.0.1
.SH DESCRIPTION
Nikola is a tool to create static websites and blogs. For full documentation and more information, please visit http://getnikola.com/
.SS "Available commands:"
@@ -36,36 +36,27 @@ dump dependency DB
nikola forget
clear successful run status from internal DB
.TP
+nikola github_deploy
+deploy the site to GitHub pages
+.TP
nikola help
show help
.TP
nikola ignore
ignore task (skip) on subsequent runs
.TP
-nikola import_blogger
-import a blogger dump
-.TP
-nikola import_feed
-import a RSS/Atom dump
-.TP
nikola import_wordpress
import a WordPress dump
.TP
nikola init
create a Nikola site in the specified folder
.TP
-nikola install_plugin
-install plugin into current site
-.TP
nikola install_theme
install theme into current site
.TP
nikola list
list tasks from dodo file
.TP
-nikola mincss
-apply mincss to the generated site
-.TP
nikola new_page
create a new page in the site
.TP
@@ -75,8 +66,8 @@ create a new blog post or site page
nikola orphans
list all orphans
.TP
-nikola run
-run tasks
+nikola plugin
+manage plugins
.TP
nikola serve
start the test webserver
diff --git a/docs/manual.txt b/docs/manual.txt
index ea080bb..dec8ac1 100644
--- a/docs/manual.txt
+++ b/docs/manual.txt
@@ -1,6 +1,6 @@
.. title: The Nikola Handbook
.. slug: handbook
-.. date: 2012/03/30 23:00
+.. date: 2012-03-30 23:00:00 UTC-03:00
.. tags:
.. link:
.. description:
@@ -8,7 +8,7 @@
The Nikola Handbook
===================
-:Version: 6.4.0
+:Version: 7.0.1
.. class:: alert alert-info pull-right
@@ -20,7 +20,7 @@ All You Need to Know
After you have Nikola `installed <#installing-nikola>`_:
-Create a empty site:
+Create a empty site (with a setup wizard):
``nikola init mysite``
You can create a site with demo files in it with ``nikola init --demo mysite``
@@ -151,7 +151,7 @@ Cost and Performance
probably serve a bazillion (technical term) pageviews from a phone using
static sites.
-Lockin
+Lock-in
On server-side blog platforms, sometimes you can't export your own data, or
it's in strange formats you can't use in other services. I have switched
blogging platforms from Advogato to PyCs to two homebrew systems, to Nikola,
@@ -201,51 +201,23 @@ This is currently lacking on detail. Considering the niche Nikola is aimed at,
I suspect that's not a problem yet. So, when I say "get", the specific details
of how to "get" something for your specific operating system are left to you.
-The short version is: ``pip install nikola``
+The short version is::
-Note that you need Python v2.6 or newer OR v3.3 or newer.
-
-For some features it may give you an error message telling you that you need to
-install something else. For example, if it tells you you need ``requests``::
-
- pip install requests
-
-And so on. Alternatively, you can install the ``requirements-full.txt`` file
-shipped with the full source tree to get everything. (or `see the file
-online
-<https://github.com/getnikola/nikola/blob/master/requirements-full.txt>`_)
+ pip install nikola
-Longer version:
-
-#. Get `Nikola <http://getnikola.com/>`_
-#. Install dependencies. To do that, either:
+Note that you need Python v2.6 or newer OR v3.3 or newer.
- #. ``pip install -r requirements.txt`` (or ``requirements-full.txt``
- for extra stuff) and ``pip install .`` or...
- #. Install your distribution's packages for all the things
- mentioned below, if they exist, or...
- #. Get all of these manually (but why?, use pip):
+Some features require **extra dependencies**. You can install them all in bulk
+by doing::
- #. Get Python, if you don't have it.
- #. Get `doit <http://pydoit.org>`_
- #. Get `docutils <http://docutils.sf.net>`_
- #. Get `Mako <http://makotemplates.org>`_
- #. Get `Pillow <http://python-imaging.github.io/>`_
- #. Get `Pygments <http://pygments.org/>`_
- #. Get `unidecode <http://pypi.python.org/pypi/Unidecode/>`_
- #. Get `lxml <http://lxml.de/>`_
- #. Get `yapsy <http://yapsy.sourceforge.net>`_
- #. Get `PyRSS2Gen <http://www.dalkescientific.com/Python/PyRSS2Gen.html>`_
- #. Get `pytz <http://pytz.sourceforge.net/>`_
- #. Get `Logbook <http://pythonhosted.org/Logbook/>`_
- #. Get `blinker <http://pythonhosted.org/blinker/>`_
- #. Get `Setuptools <http://pythonhosted.org/setuptools/>`_
- #. If using Python 2, get `configparser <http://pypi.python.org/pypi/configparser/3.2.0r3>`_
+ pip install nikola[extras]
-#. run ``python setup.py install``
+Alternatively, you can install those packages one-by-one, when required (Nikola
+will tell you what packages are needed)
-After that, run ``nikola init --demo sitename`` and that will create a folder called
-``sitename`` containing a functional demo site.
+After that, run ``nikola init --demo sitename`` and that will run the setup
+wizard, which will create a folder called ``sitename`` containing a functional
+demo site.
Nikola is packaged for some Linux distributions, you may get that instead. e.g.
If you are running Arch Linux, there are AUR packages, available in Python 2/3
@@ -415,19 +387,17 @@ Nikola also has other commands besides ``build``::
nikola doit_auto automatically execute tasks when a dependency changes
nikola dumpdb dump dependency DB
nikola forget clear successful run status from internal DB
+ nikola github_deploy deploy the site to GitHub pages
nikola help show help
nikola ignore ignore task (skip) on subsequent runs
- nikola import_blogger import a blogger dump
- nikola import_feed import a RSS/Atom dump
nikola import_wordpress import a WordPress dump
nikola init create a Nikola site in the specified folder
- nikola install_plugin install plugin into current site
nikola install_theme install theme into current site
nikola list list tasks from dodo file
- nikola mincss apply mincss to the generated site
+ nikola new_page create a new page in the site
nikola new_post create a new blog post or site page
nikola orphans list all orphans
- nikola run run tasks
+ nikola plugin manage plugins
nikola serve start the test webserver
nikola strace use strace to list file_deps and targets
nikola tabcompletion generate script for tab-complention
@@ -439,11 +409,11 @@ Nikola also has other commands besides ``build``::
The ``serve`` command starts a web server so you can see the site you are creating::
- $ nikola serve
+ $ nikola serve -b
Serving HTTP on 127.0.0.1 port 8000 ...
-After you do this, you can point your web browser to http://localhost:8000 and you should see
+After you do this, a web browser opens at http://127.0.0.1:8000/ and you should see
the sample site. This is useful as a "preview" of your work.
By default, the ``serve`` command runs the web server on port 8000 on the IP address 127.0.0.1.
@@ -466,9 +436,11 @@ It can be placed in a separate file by using the ``-2`` option, but it's general
easier to keep it in a single location.
The contents of your post have to be written (by default) in `reStructuredText <http://docutils.sf.net>`__
-but you can use a lot of different markups using the ``-f`` option. Currently
-Nikola supports bbcode, wiki, markdown, html, txt2tags and textile in addition
-to reStructuredText.
+but you can use a lot of different markups using the ``-f`` option.
+
+Currently Nikola supports reStructuredText, Markdown, IPython Notebooks, HTML as input,
+can also use Pandoc for conversion, and has support for BBCode, CreoleWiki, txt2tags, Textile
+and more via `plugins <http://plugins.getnikola.com>`__.
You can control what markup compiler is used for each file extension with the ``COMPILERS``
option. The default configuration expects them to be placed in ``posts`` but that can be
@@ -487,7 +459,7 @@ The content of that file is as follows::
.. title: How to make money
.. slug: how-to-make-money
- .. date: 2012/09/15 19:52:05
+ .. date: 2012-09-15 19:52:05 UTC
.. tags:
.. link:
.. description:
@@ -562,10 +534,21 @@ to your configuration::
How to make money
how-to-make-money
- 2012/09/15 19:52:05
+ 2012-09-15 19:52:05 UTC
+
+ However, starting with Nikola v7, you can now use ``.meta`` files and put
+ all metadata you want, complete with the explanations — they look just like
+ the beginning of our reST files.
+
+ .. title: How to make money
+ .. slug: how-to-make-money
+ .. date: 2012-09-15 19:52:05 UTC
+
+ Both file formats are supported; however, the new format is preferred, if
+ possible.
If you are writing a multilingual site, you can also create a per-language
-post file (for example: ``how-to-make-money.txt.es`` with the default TRANSLATIONS_PATTERN, see below).
+post file (for example: ``how-to-make-money.es.txt`` with the default TRANSLATIONS_PATTERN, see below).
This one can replace metadata of the default language, for example:
* The translated title for the post or page
@@ -574,20 +557,13 @@ This one can replace metadata of the default language, for example:
The pattern used for finding translations is controlled by the
TRANSLATIONS_PATTERN variable in your configuration file.
-The default as in the example above is to append the language code to the
-filename path to identify a translation of a file, so the German translation
-of ``some_file.rst`` should be named ``some_file.rst.de``. This is because
-the TRANSLATIONS_PATTERN variable is by default set to::
-
- TRANSLATIONS_PATTERN = "{path}.{ext}.{lang}"
-
-However, if you don't want your Polish input files to be considered
-Perl code (e.g. ``some_file.rst.pl``), you could use this pattern::
+The default is to put the language code before the file extension,
+so the German translation of ``some_file.rst`` should be named
+``some_file.de.rst``. This is because the TRANSLATIONS_PATTERN variable is by
+default set to::
TRANSLATIONS_PATTERN = "{path}.{lang}.{ext}"
-Note that this pattern will become the default in v7.0.0.
-
.. note:: Considered languages
nikola will only look for translation of input files for languages
@@ -596,7 +572,7 @@ Note that this pattern will become the default in v7.0.0.
You can edit these files with your favourite text editor, and once you are happy
with the contents, generate the pages as explained in `Getting Started`_
-Currently supported languages are
+Currently supported languages are:
* Basque
* Bulgarian
@@ -612,14 +588,16 @@ Currently supported languages are
* French
* German
* Greek
+* Hindi
* Italian
* Japanese
* Norwegian Bokmål
* Persian
* Polish
-* Portuguese
+* Portuguese (Brasil)
* Russian
-* Slovenian
+* Slovak
+* Slovene
* Spanish
* Turkish
* Urdu
@@ -640,7 +618,7 @@ and ``PAGES`` configuration options::
#
# That fragment could have an associated metadata file (whatever/thing.meta),
# and optionally translated files (example for Spanish, with code "es"):
- # whatever/thing.txt.es and whatever/thing.meta.es
+ # whatever/thing.es.txt and whatever/thing.es.meta
#
# This assumes you use the default TRANSLATIONS_PATTERN.
#
@@ -744,10 +722,10 @@ published immediately. Posts dated in the future are *not* deployed by default
deployed site, you can set ``DEPLOY_FUTURE = True`` in your configuration.
Generally, you want FUTURE_IS_NOW and DEPLOY_FUTURE to be the same value.
-Retired Posts
-~~~~~~~~~~~~~
+Private (formerly retired) Posts
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you add a "retired" tag to a post, then it will not be shown in indexes and feeds.
+If you add a "private" tag to a post, then it will not be shown in indexes and feeds.
It *will* be compiled, and if you deploy it it *will* be made available, so it will
not generate 404s for people who had linked to it.
@@ -792,15 +770,6 @@ All these posts get queued up according to your schedule, but note
that you will anyway need to build and deploy your site for the posts
to appear online. You can have a cron job that does this regularly.
-An additional setting (``SCHEDULE_FORCE_TODAY = True``) lets you tell
-Nikola to make the post today, if you run the ``new_post --schedule``
-after the scheduled hour has passed, and there is no other post
-at/after the scheduled hour. Concretely, say, you run the ``nikola
-new_post -s`` command at 10am on a Monday (with the schedule rule set
-to the same as above), with no other post on Monday, at/after 7am,
-setting ``SCHEDULE_FORCE_TODAY = True`` will have your post scheduled
-to Monday, instead of being scheduled to Wednesday 7am.
-
Post Types
~~~~~~~~~~
@@ -865,11 +834,17 @@ commented.
You surely want to edit these options::
# Data about this site
- BLOG_TITLE = "Demo Site"
- SITE_URL = "http://getnikola.com"
+ BLOG_AUTHOR = "Your Name" # (translatable)
+ BLOG_TITLE = "Demo Site" # (translatable)
+ SITE_URL = "http://getnikola.com/"
BLOG_EMAIL = "joe@demo.site"
- BLOG_DESCRIPTION = "This is a demo site for Nikola."
+ BLOG_DESCRIPTION = "This is a demo site for Nikola." # (translatable)
+Some options are demarked with a (translatable) comment above or right next to
+them. For those options, two types of values can be provided:
+
+ * a string, which will be used for all languages
+ * a dict of language-value pairs, to have different values in each language
Customizing Your Site
---------------------
@@ -887,11 +862,11 @@ CSS tweaking
with a `custom theme <theming.html>`__.
If you want to use LESS_ or Sass_ for your custom CSS, or the theme you use
- contains LESS or Sass code that you want to override, create a ``less`` or
+ contains LESS or Sass code that you want to override, you will need to install
+ the `LESS plugin <http://plugins.getnikola.com/#less>`__ or
+ `SASS plugin <http://plugins.getnikola.com/#sass>`__ create a ``less`` or
``sass`` directory in your site root, put your ``.less`` or ``.scss`` files
- there and a targets file containing the files you want compiled. Any
- ``.less`` or ``.scss`` files from the theme chain that you want to use will
- need to be included in your files.
+ there and a targets file containing the list of files you want compiled.
.. _LESS: http://lesscss.org/
.. _Sass: http://sass-lang.com/
@@ -931,7 +906,9 @@ Navigation Links
Footer
``CONTENT_FOOTER`` is displayed, small at the bottom of all pages, I use it for
the copyright notice. The default shows a text formed using ``BLOG_AUTHOR``,
- ``BLOG_EMAIL``, the date and ``LICENSE``.
+ ``BLOG_EMAIL``, the date and ``LICENSE``. Note you need to use
+ ``CONTENT_FOOTER_FORMATS`` instead of regular str.format or %-formatting,
+ for compatibility with the translatable settings feature.
BODY_END
This option lets you define a HTML snippet that will be added at the bottom of body.
@@ -975,8 +952,8 @@ Nikola has a built-in theme download/install mechanism to install those themes
$ nikola install_theme -l
Themes:
-------
- base-jinja
blogtxt
+ bootstrap3-gradients
@@ -1032,6 +1009,34 @@ Other interesting ideas are using
for that matter), using `lftp mirror <http://lftp.yar.ru/>`_ or unison, or Dropbox, or
Ubuntu One. Any way you can think of to copy files from one place to another is good enough.
+Deploying to GitHub
+~~~~~~~~~~~~~~~~~~~
+
+Nikola provides a separate command ``github_deploy`` to deploy your
+site to GitHub pages. The command builds the site, commits the
+output to a gh-pages branch and pushes the output to GitHub.
+
+The branch to use for committing the sources can be changed using the
+``GITHUB_DEPLOY_BRANCH`` option in your config. For a
+user.github.io/organization.github.io, this MUST be set to ``master``,
+and the branch containing the sources must be changed to something
+else, like ``deploy``, using the ``GITHUB_SOURCE_BRANCH`` option. The
+remote name to which the changes are pushed is ``origin`` by default,
+and can be changed using the ``GITHUB_REMOTE_NAME`` option. You also,
+obviously, need to have ``git`` on your PATH, and should be able to
+push to the repository specified as the remote.
+
+This command performs the following actions, when it is run:
+
+1. Ensure that your site is a git repository, and git is on the PATH.
+2. Check for changes, and prompt the user to continue, if required.
+3. Build the site
+4. Clean any files that are "unknown" to Nikola.
+5. Create a deploy branch, if one doesn't exist.
+6. Commit the output to this branch. (NOTE: Any untracked source
+ files, may get committed at this stage, on the wrong branch!)
+7. Push and deploy!
+
Comments and Annotations
------------------------
@@ -1219,9 +1224,6 @@ optipng
jpegoptim
Compress JPEG files using `jpegoptim <http://www.kokkonen.net/tjko/projects.html>`_
-tidy
- Apply `tidy <http://tidy.sourceforge.net/>`_ to HTML files
-
typogrify
Improve typography using `typogrify <https://github.com/mintchaos/typogrify>`_
@@ -1238,7 +1240,7 @@ different ones, or about other web servers, please share!
#. Enable compression in Apache::
- AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
+ AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript
#. If even after you did the previous step the CSS files are not sent compressed::
@@ -1513,103 +1515,6 @@ and the authors Twitter user ID is found below.
}
-Extra Plugins
--------------
-
-These are plugins that may not be widely used or that are a bit too radical or
-experimental for the general public.
-
-To enable them for your site please look for `ENABLED_EXTRAS` in your ``conf.py``.
-
-Planetoid
-~~~~~~~~~
-
-This plugin converts Nikola into the equivalent of `Planet <http://www.planetplanet.org/>`_
-a feed aggregator. It requires `PeeWee <https://github.com/coleifer/peewee>`_ and
-`Feedparser <http://code.google.com/p/feedparser/>`_ to work.
-
-It has a configuration option: PLANETOID_REFRESH which is the number of minutes
-before retrying a feed (defaults to 60).
-
-You need to create a ``feeds`` file containing the data of which feeds you want to
-aggregate. The format is very simple::
-
- # Roberto Alsina
- http://feeds2.feedburner.com/PostsInLateralOpinionAboutPython
- Roberto Alsina
-
-#. Lines that start with ``#`` are comments and ignored.
-#. Lines that start with http are feed URLs.
-#. URL lines have to be followed by the "real name" of the feed.
-
-After all that is in place, just run ``nikola build`` and you'll get
-a planet.
-If you run ``nikola build`` for the first time you need to actually issue
-the command three times until the planet is build.
-
-There is a special theme for the planets called `site-planetoid`. To use
-this set `THEME` in your ``conf.py`` to ``'site-planetoid'``.
-This is special in the case that it redirects users to the original URL of the post
-when they try to open a post.
-
-Local Search
-~~~~~~~~~~~~
-
-If you don't want to depend on Google or DuckDuckGo to implement search for you,
-or just want it to work even if you are offline, enable this plugin and the
-search will be performed client side.
-
-This plugin implements a Tipue-based local search for your site.
-
-To use it, enable local_search in ENABLED_EXTRAS in your sites conf.py
-
-After you build your site, you will have several new files in assets/css and assets/js
-and a tipue_search.html that you can use as a basis for using this in your site.
-
-For more information about how to customize it and use it, please refer to the tipue
-docs at http://www.tipue.com/search/
-
-Tipue is under an MIT license (see MIT-LICENSE.txt)
-
-Here's a set of example settings for conf.py that should work nicely with the "bootstrap" theme::
-
- SEARCH_FORM = """
- <span class="navbar-form pull-left">
- <input type="text" id="tipue_search_input">
- </span>"""
-
- BODY_END = """
- <script type="text/javascript" src="/assets/js/tipuesearch_set.js"></script>
- <script type="text/javascript" src="/assets/js/tipuesearch.js"></script>
- <script type="text/javascript">
- $(document).ready(function() {
- $('#tipue_search_input').tipuesearch({
- 'mode': 'json',
- 'contentLocation': '/assets/js/tipuesearch_content.json',
- 'showUrl': false
- });
- });
- </script>
- """
-
- EXTRA_HEAD_DATA = """
- <link rel="stylesheet" type="text/css" href="/assets/css/tipuesearch.css">
- <div id="tipue_search_content" style="margin-left: auto; margin-right: auto; padding: 20px;"></div>
- """
-
- ENABLED_EXTRAS = [ 'local_search' ]
-
-
-The <div> in EXTRA_HEAD_DATA is a hack but it will migrate into the <body> of the
-documents thanks to magic, and will hold the search results after the user searches.
-
-Mustache
-~~~~~~~~
-
-This task gives you a ``mustache.html`` file which lets you access your whole
-blog without reloading the page, using client-side templates. Makes it much
-faster and modern ;-)
-
Custom Plugins
--------------
@@ -1623,10 +1528,10 @@ Getting Extra Plugins
If you want extra plugins, there is also the `Plugins Index <http://plugins.getnikola.com/>`_.
-Similarly to themes, there is a nice, built-in command to install them —
-``install_plugin``::
+Similarly to themes, there is a nice, built-in command to manage them —
+``plugin``::
- $ nikola install_plugin -l
+ $ nikola plugin -l
Plugins:
--------
helloworld
@@ -1634,7 +1539,7 @@ Similarly to themes, there is a nice, built-in command to install them —
- $ nikola install_plugin helloworld
+ $ nikola plugin --install helloworld
[2013-10-12T16:51:56Z] NOTICE: install_plugin: Downloading: http://plugins.getnikola.com/v6/helloworld.zip
[2013-10-12T16:51:58Z] NOTICE: install_plugin: Extracting: helloworld into plugins
plugins/helloworld/requirements.txt
@@ -1649,6 +1554,29 @@ Similarly to themes, there is a nice, built-in command to install them —
# Should the Hello World plugin say “BYE” instead?
BYE_WORLD = False
+Then you also can uninstall your plugins::
+
+ $ nikola plugin --uninstall tags
+ [2014-04-15T08:59:24Z] WARNING: plugin: About to uninstall plugin: tags
+ [2014-04-15T08:59:24Z] WARNING: plugin: This will delete /home/ralsina/foo/plugins/tags
+ Are you sure? [y/n] y
+ [2014-04-15T08:59:26Z] WARNING: plugin: Removing /home/ralsina/foo/plugins/tags
+
+And upgrade them::
+
+ $ nikola plugin --upgrade
+ [2014-04-15T09:00:18Z] WARNING: plugin: This is not very smart, it just reinstalls some plugins and hopes for the best
+ Will upgrade 1 plugins: graphviz
+ Upgrading graphviz
+ [2014-04-15T09:00:20Z] INFO: plugin: Downloading: http://plugins.getnikola.com/v7/graphviz.zip
+ [2014-04-15T09:00:20Z] INFO: plugin: Extracting: graphviz into /home/ralsina/.nikola/plugins/
+ [2014-04-15T09:00:20Z] NOTICE: plugin: This plugin has third-party dependencies you need to install manually.
+ Contents of the requirements-nonpy.txt file:
+
+ Graphviz
+ http://www.graphviz.org/
+
+ You have to install those yourself or through a package manager.
You can also share plugins you created with the community! Visit the
`GitHub repository <https://github.com/getnikola/plugins>`__ to find out more.
@@ -1657,6 +1585,19 @@ You can use the plugins in this repository without installing them into your
site, by cloning the repository and adding the path of the plugins directory to
the ``EXTRA_PLUGINS_DIRS`` list in your configuration.
+Shell Tab Completion
+--------------------
+
+Since Nikola is a command line tool, and this is the 21st century, it's handy to have smart tab-completion
+so that you don't have to type the full commands.
+
+To enable this, you can use the ``nikola tabcompletion`` command like this, depending on your shell::
+
+ $ nikola tabcompletion --shell bash --hardcode-tasks > _nikola_bash
+ $ nikola tabcompletion --shell zsh --hardcode-tasks > _nikola_zsh
+
+The ``--hardcode-tasks`` adds tasks to the completion and may need updating periodically.
+
License
-------
diff --git a/docs/social_buttons.txt b/docs/social_buttons.txt
index de7fecf..1d6c5b5 100644
--- a/docs/social_buttons.txt
+++ b/docs/social_buttons.txt
@@ -1,6 +1,6 @@
.. title: Alternative Social Buttons
.. slug: social_buttons
-.. date: 2013/08/19 23:00
+.. date: 2013-08-19 23:00:00 UTC-03:00
.. tags:
.. link:
.. description:
@@ -8,7 +8,7 @@
Using Alternative Social Buttons with Nikola
============================================
-:Version: 6.4.0
+:Version: 7.0.1
.. class:: alert alert-info pull-right
@@ -33,7 +33,7 @@ the bottom right of the page, provided by Addthis. This is the HTML code for tha
<li><a class="addthis_button_twitter"></a>
</ul>
</div>
- <script type="text/javascript" src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script>
+ <script src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script>
<!-- End of social buttons -->
"""
@@ -96,8 +96,7 @@ is the HTML code suggested by ShareNice:
data-services="plus.google.com,facebook.com,digg.com,email,delicious.com,twitter.com"
style="float:right"></div>"""
- BODY_END = """<script src="http://graingert.co.uk/shareNice/code.js"
- type="text/javascript"></script>"""
+ BODY_END = """<script src="http://graingert.co.uk/shareNice/code.js"></script>"""
And you should now see a sharing box at the bottom right of the page.
@@ -169,8 +168,8 @@ Edit your ``conf.py``:
.. code-block:: python
BODY_END = """
- <script type="text/javascript" src="/javascripts/jquery.socialshareprivacy.min.js"></script>
- <script type="text/javascript">
+ <script src="/javascripts/jquery.socialshareprivacy.min.js"></script>
+ <script>
$(document).ready(function () {
$('.share').socialSharePrivacy();
});
diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py
index faf2db1..20a0578 100644
--- a/docs/sphinx/conf.py
+++ b/docs/sphinx/conf.py
@@ -15,12 +15,12 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
+# needs_sphinx = '1.0'
from __future__ import unicode_literals
@@ -40,7 +40,7 @@ templates_path = ['_templates']
source_suffix = '.txt'
# The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
@@ -54,19 +54,19 @@ copyright = '2012-2014, The Nikola Contributors'
# built documents.
#
# The short X.Y version.
-version = '6.4.0'
+version = '7.0.1'
# The full version, including alpha/beta/rc tags.
-release = '6.4.0'
+release = '7.0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-#language = None
+# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+# today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@@ -74,27 +74,27 @@ exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
-#default_role = None
+# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
-#keep_warnings = False
+# keep_warnings = False
# -- Options for HTML output ----------------------------------------------
@@ -106,26 +106,26 @@ html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
-#html_theme_options = {}
+# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
-#html_title = None
+# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-#html_favicon = None
+# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -135,48 +135,48 @@ html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
-#html_extra_path = []
+# html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
+# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
# If false, no module index is generated.
-#html_domain_indices = True
+# html_domain_indices = True
# If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'Nikoladoc'
@@ -186,13 +186,13 @@ htmlhelp_basename = 'Nikoladoc'
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
- #'papersize': 'letterpaper',
+ # 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
- #'pointsize': '10pt',
+ # 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
- #'preamble': '',
+ # 'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
@@ -205,23 +205,23 @@ latex_documents = [
# The name of an image file (relative to this directory) to place at the top of
# the title page.
-#latex_logo = None
+# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
# If true, show page references after internal links.
-#latex_show_pagerefs = False
+# latex_show_pagerefs = False
# If true, show URL addresses after external links.
-#latex_show_urls = False
+# latex_show_urls = False
# Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
# If false, no module index is generated.
-#latex_domain_indices = True
+# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
@@ -234,7 +234,7 @@ man_pages = [
]
# If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
@@ -249,15 +249,15 @@ texinfo_documents = [
]
# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
+# texinfo_appendices = []
# If false, no module index is generated.
-#texinfo_domain_indices = True
+# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
+# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
-#texinfo_no_detailmenu = False
+# texinfo_no_detailmenu = False
primary_domain = None
diff --git a/docs/theming.txt b/docs/theming.txt
index b370948..bc5ad1f 100644
--- a/docs/theming.txt
+++ b/docs/theming.txt
@@ -1,6 +1,6 @@
.. title: Theming Nikola
.. slug: theming
-.. date: 2012/03/13 12:00
+.. date: 2012-03-13 12:00:00 UTC-03:00
.. tags:
.. link:
.. description:
@@ -8,7 +8,7 @@
Theming Nikola
==============
-:Version: 6.4.0
+:Version: 7.0.1
:Author: Roberto Alsina <ralsina@netmanagers.com.ar>
.. class:: alert alert-info pull-right
diff --git a/docs/upgrading-to-v6.txt b/docs/upgrading-to-v6.txt
index ab89614..765f901 100644
--- a/docs/upgrading-to-v6.txt
+++ b/docs/upgrading-to-v6.txt
@@ -1,6 +1,6 @@
.. title: Upgrading to v6
.. slug: upgrading-to-v6
-.. date: 2013/08/23 23:00
+.. date: 2013-08-23 23:00:00 UTC-03:00
.. tags:
.. link:
.. description:
@@ -8,7 +8,7 @@
Upgrading to v6
===============
-:Version: 6.4.0
+:Version: 7.0.1
.. class:: lead
diff --git a/dodo.py b/dodo.py
index 27c39fa..66163f2 100644
--- a/dodo.py
+++ b/dodo.py
@@ -12,7 +12,7 @@ DOIT_CONFIG = {
def recursive_glob(path, pattern):
"""recursively walk path directories and return files matching the pattern"""
- for root, dirnames, filenames in os.walk(path):
+ for root, dirnames, filenames in os.walk(path, followlinks=True):
for filename in fnmatch.filter(filenames, pattern):
yield os.path.join(root, filename)
@@ -20,8 +20,8 @@ def recursive_glob(path, pattern):
def task_flake8():
"""flake8 - static check for python files"""
yield {
- 'name': os.getcwd(),
- 'actions': ['flake8 --ignore=E501 .'],
+ 'name': os.path.join(os.getcwd(), 'nikola'),
+ 'actions': ['flake8 --ignore=E501 nikola/'],
}
@@ -56,19 +56,27 @@ def task_locale():
return {'actions': [set_nikola_test_locales], 'verbosity': 2}
+def task_doctest():
+ """run doctests with py.test"""
+ return {
+ 'actions': ['py.test --doctest-modules nikola/'],
+ 'verbosity': 2,
+ }
+
+
def task_test():
- """run unit-tests using nose"""
+ """run unit-tests using py.test"""
return {
- 'task_dep': ['locale'],
- 'actions': ['nosetests --with-doctest --doctest-options=+NORMALIZE_WHITESPACE --logging-filter=-yapsy'],
+ 'task_dep': ['locale', 'doctest'],
+ 'actions': ['py.test tests/'],
}
def task_coverage():
- """run unit-tests using nose"""
+ """run unit-tests using py.test, with coverage reporting"""
return {
- 'task_dep': ['locale'],
- 'actions': ['nosetests --with-coverage --cover-package=nikola --with-doctest --doctest-options=+NORMALIZE_WHITESPACE --logging-filter=-yapsy'],
+ 'task_dep': ['locale', 'doctest'],
+ 'actions': ['py.test --cov nikola --cov-report term-missing tests/'],
'verbosity': 2,
}
diff --git a/logo/favicon.png b/logo/favicon.png
new file mode 100644
index 0000000..3e5ddab
--- /dev/null
+++ b/logo/favicon.png
Binary files differ
diff --git a/logo/favicon.svg b/logo/favicon.svg
new file mode 100644
index 0000000..b3eec96
--- /dev/null
+++ b/logo/favicon.svg
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2991"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:docname="Nikola Favicon">
+ <defs
+ id="defs2993" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.627417"
+ inkscape:cx="17.60392"
+ inkscape:cy="6.8251939"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ borderlayer="true"
+ objecttolerance="1"
+ gridtolerance="1"
+ inkscape:window-width="1920"
+ inkscape:window-height="1021"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3121"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="false" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata2996">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1036.3622)">
+ <path
+ style="fill:#f5ab14;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 11.1875,2 0,8.0625 L 9,7.2432222 c 0.00713,4.4146018 0,-0.2133286 -0.00989,4.2160298 L 10.96875,14 14,14 14,2 z"
+ transform="translate(0,1036.3622)"
+ id="path28-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="fill:#333333;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2,2 0,12 2.8125,0 0,-7.90625 3.1709272,4.0996 c 0,0 0.00477,-0.06447 0.016573,-4.254117 L 4.9375,2 z"
+ transform="translate(0,1036.3622)"
+ id="path28"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ </g>
+</svg>
diff --git a/logo/nikola-50px-transparent.png b/logo/nikola-50px-transparent.png
new file mode 100644
index 0000000..d09b0e2
--- /dev/null
+++ b/logo/nikola-50px-transparent.png
Binary files differ
diff --git a/logo/nikola.png b/logo/nikola.png
new file mode 100644
index 0000000..145f841
--- /dev/null
+++ b/logo/nikola.png
Binary files differ
diff --git a/logo/nikola.svg b/logo/nikola.svg
new file mode 100644
index 0000000..baadf90
--- /dev/null
+++ b/logo/nikola.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0, 0, 1000, 750">
+<title>Nikola Logo</title>
+<defs>
+<clipPath id="a">
+<path d="M0 5999.97v-5999.97h7999.99v5999.97"/>
+</clipPath>
+</defs>
+<g clip-path="url(#a)">
+<path d="M0 750h999.999v-749.996h-999.999v749.996z" fill="#3e4445"/>
+<path d="M554.759 364.245c-6.771 6.707-15.61 10.064-26.48 10.064h-3.393c-10.955 0-19.881-3.356-26.719-10.064-6.866-6.713-10.287-17.927-10.287-33.735 0-14.883 3.474-25.652 10.481-32.281 6.981-6.644 16.098-9.943 27.304-9.943h1.841c11.109 0 20.133 3.299 27.051 9.943 6.931 6.629 10.389 17.399 10.389 32.281 0 15.807-3.406 27.023-10.188 33.735zm22.008-80.249c-12.851-11.495-29.731-17.241-50.659-17.241l-1.474.013c-19.999.446-36.214 6.191-48.684 17.229-12.977 11.479-19.455 27.622-19.455 48.386 0 19.626 6.433 35.12 19.344 46.422 12.886 11.332 29.35 16.997 49.384 16.997h2.734c19.83 0 36.133-5.665 48.916-16.997 12.775-11.303 19.154-26.796 19.154-46.422 0-20.764-6.412-36.907-19.26-48.386" fill="#cccfd5"/>
+<path d="M286.11 395.803h29.795v-126.282h-29.795v126.282z" fill="#cccfd5"/>
+<path d="M140.713 395.803v-126.282h30.446l64.263 84.907v-84.907h29.039v126.282h-31.42l-63.278-83.039v83.039h-29.05" fill="#cccfd5"/>
+<path d="M336.582 395.803h29.797v-126.282h-29.797v126.282z" fill="#cccfd5"/>
+<path d="M365.87 334.235l57.465-63.136h39.651l-59.885 63.136 60.694 61.568h-36.422l-61.502-61.568" fill="#cccfd5"/>
+<path d="M642.86 293.668v-22.927h-30.578v125.063h123.499l45.564-95.544 33.792 66.11-9.796-76.672-9.605-21.808h-29.973l-50.356 106.715h-72.547v-80.936" fill="#cccfd5"/>
+<path d="M818.813 312.84l40.474 83.141h-44.359l37.172 87.267-70.755-108.058h46.164l-8.696-62.351" fill="#f5ab14"/>
+</g>
+</svg>
diff --git a/nikola/__init__.py b/nikola/__init__.py
index 787ce8e..cf4d2e5 100644
--- a/nikola/__init__.py
+++ b/nikola/__init__.py
@@ -27,7 +27,7 @@
from __future__ import absolute_import
import os
-__version__ = "6.4.0"
+__version__ = "7.0.1"
DEBUG = bool(os.getenv('NIKOLA_DEBUG'))
from .nikola import Nikola # NOQA
diff --git a/nikola/__main__.py b/nikola/__main__.py
index 715f5b3..455926d 100644
--- a/nikola/__main__.py
+++ b/nikola/__main__.py
@@ -28,6 +28,10 @@ from __future__ import print_function, unicode_literals
from operator import attrgetter
import os
import shutil
+try:
+ import readline # NOQA
+except ImportError:
+ pass # This is only so raw_input/input does nicer things if it's available
import sys
import traceback
@@ -40,39 +44,45 @@ from doit.cmd_run import Run as DoitRun
from doit.cmd_clean import Clean as DoitClean
from doit.cmd_auto import Auto as DoitAuto
from logbook import NullHandler
+from blinker import signal
from . import __version__
+from .plugin_categories import Command
from .nikola import Nikola
-from .utils import _reload, sys_decode, get_root_dir, LOGGER, STRICT_HANDLER
-
+from .utils import _reload, sys_decode, get_root_dir, req_missing, LOGGER, STRICT_HANDLER, ColorfulStderrHandler
config = {}
-def main(args):
+def main(args=None):
+ colorful = False
+ if sys.stderr.isatty() and os.name != 'nt':
+ colorful = True
+
+ ColorfulStderrHandler._colorful = colorful
+
+ if args is None:
+ args = sys.argv[1:]
quiet = False
- if len(args) > 0 and args[0] == 'build' and '--strict' in args:
+ if len(args) > 0 and args[0] == b'build' and b'--strict' in args:
LOGGER.notice('Running in strict mode')
STRICT_HANDLER.push_application()
- if len(args) > 0 and args[0] == 'build' and '-q' in args or '--quiet' in args:
+ if len(args) > 0 and args[0] == b'build' and b'-q' in args or b'--quiet' in args:
nullhandler = NullHandler()
nullhandler.push_application()
quiet = True
global config
- colorful = False
- if sys.stderr.isatty():
- colorful = True
- try:
- import colorama
- colorama.init()
- except ImportError:
- if os.name == 'nt':
- colorful = False
-
- root = get_root_dir()
- if root:
- os.chdir(root)
+ # Those commands do not require a `conf.py`. (Issue #1132)
+ # Moreover, actually having one somewhere in the tree can be bad, putting
+ # the output of that command (the new site) in an unknown directory that is
+ # not the current working directory. (does not apply to `version`)
+ argname = args[0] if len(args) > 0 else None
+ # FIXME there are import plugins in the repo, so how do we handle this?
+ if argname and argname not in ['init', 'version'] and not argname.startswith('import_'):
+ root = get_root_dir()
+ if root:
+ os.chdir(root)
sys.path.append('')
try:
@@ -86,18 +96,46 @@ def main(args):
sys.exit(1)
config = {}
- config.update({'__colorful__': colorful})
+ invariant = False
+
+ if len(args) > 0 and args[0] == b'build' and b'--invariant' in args:
+ try:
+ import freezegun
+ freeze = freezegun.freeze_time("2014-01-01")
+ freeze.start()
+ invariant = True
+ except ImportError:
+ req_missing(['freezegun'], 'perform invariant builds')
+
+ if config:
+ if os.path.exists('plugins') and not os.path.exists('plugins/__init__.py'):
+ with open('plugins/__init__.py', 'w') as fh:
+ fh.write('# Plugin modules go here.')
+
+ config['__colorful__'] = colorful
+ config['__invariant__'] = invariant
+ config['__quiet__'] = quiet
site = Nikola(**config)
- return DoitNikola(site, quiet).run(args)
+ _ = DoitNikola(site, quiet).run(args)
+
+ if site.invariant:
+ freeze.stop()
+ return _
class Help(DoitHelp):
- """show Nikola usage instead of doit """
+ """show Nikola usage."""
@staticmethod
def print_usage(cmds):
"""print nikola "usage" (basic help) instructions"""
+ # Remove 'run'. Nikola uses 'build', though we support 'run' for
+ # people used to it (eg. doit users).
+ # WARNING: 'run' is the vanilla doit command, without support for
+ # --strict, --invariant and --quiet.
+ del cmds['run']
+
print("Nikola is a tool to create static websites and blogs. For full documentation and more information, please visit http://getnikola.com/\n\n")
print("Available commands:")
for cmd in sorted(cmds.values(), key=attrgetter('name')):
@@ -123,6 +161,15 @@ class Build(DoitRun):
)
opts.append(
{
+ 'name': 'invariant',
+ 'long': 'invariant',
+ 'default': False,
+ 'type': bool,
+ 'help': "Generate invariant output (for testing only!).",
+ }
+ )
+ opts.append(
+ {
'name': 'quiet',
'long': 'quiet',
'short': 'q',
@@ -165,6 +212,7 @@ class NikolaTaskLoader(TaskLoader):
else:
DOIT_CONFIG = {
'reporter': ExecutedOnlyReporter,
+ 'outfile': sys.stderr,
}
DOIT_CONFIG['default_tasks'] = ['render_site', 'post_render']
tasks = generate_tasks(
@@ -173,6 +221,7 @@ class NikolaTaskLoader(TaskLoader):
latetasks = generate_tasks(
'post_render',
self.nikola.gen_tasks('post_render', "LateTask", 'Group of tasks to be executes after site is rendered.'))
+ signal('initialized').send(self.nikola)
return tasks + latetasks, DOIT_CONFIG
@@ -183,13 +232,14 @@ class DoitNikola(DoitMain):
def __init__(self, nikola, quiet=False):
self.nikola = nikola
+ nikola.doit = self
self.task_loader = self.TASK_LOADER(nikola, quiet)
def get_commands(self):
# core doit commands
cmds = DoitMain.get_commands(self)
# load nikola commands
- for name, cmd in self.nikola.commands.items():
+ for name, cmd in self.nikola._commands.items():
cmds[name] = cmd
return cmds
@@ -198,21 +248,36 @@ class DoitNikola(DoitMain):
args = self.process_args(cmd_args)
args = [sys_decode(arg) for arg in args]
- if len(args) == 0 or any(arg in ["--help", '-h'] for arg in args):
+ if len(args) == 0:
cmd_args = ['help']
args = ['help']
- # Hide run because Nikola uses build
- sub_cmds.pop('run')
- if len(args) == 0 or any(arg in ["--version", '-V'] for arg in args):
+
+ if '--help' in args or '-h' in args:
+ new_cmd_args = ['help'] + cmd_args
+ new_args = ['help'] + args
+
+ cmd_args = []
+ args = []
+
+ for arg in new_cmd_args:
+ if arg not in ('--help', '-h'):
+ cmd_args.append(arg)
+ for arg in new_args:
+ if arg not in ('--help', '-h'):
+ args.append(arg)
+
+ if any(arg in ("--version", '-V') for arg in args):
cmd_args = ['version']
args = ['version']
- if len(args) == 0 or args[0] not in sub_cmds.keys() or \
- args[0] == 'build':
- # Check for conf.py before launching run
+ if args[0] not in sub_cmds.keys():
+ LOGGER.error("Unknown command {0}".format(args[0]))
+ return False
+ if not isinstance(sub_cmds[args[0]], (Command, Help)): # Is a doit command
if not self.nikola.configured:
LOGGER.error("This command needs to run inside an "
"existing Nikola site.")
return False
+
return super(DoitNikola, self).run(cmd_args)
@staticmethod
diff --git a/nikola/conf.py.in b/nikola/conf.py.in
index b398ac3..2f40b59 100644
--- a/nikola/conf.py.in
+++ b/nikola/conf.py.in
@@ -4,13 +4,22 @@
from __future__ import unicode_literals
import time
-#!! This is the configuration of Nikola. !!#
-#!! You should edit it to your liking. !!#
+# !! This is the configuration of Nikola. !! #
+# !! You should edit it to your liking. !! #
+
+
+# ! Some settings can be different in different languages.
+# ! A comment stating (translatable) is used to denote those.
+# ! There are two ways to specify a translatable setting:
+# ! (a) BLOG_TITLE = "My Blog"
+# ! (b) BLOG_TITLE = {"en": "My Blog", "es": "Mi Blog"}
+# ! Option (a) is used when you don't want that setting translated.
+# ! Option (b) is used for settings that are different in different languages.
# Data about this site
-BLOG_AUTHOR = ${BLOG_AUTHOR}
-BLOG_TITLE = ${BLOG_TITLE}
+BLOG_AUTHOR = ${BLOG_AUTHOR} # (translatable)
+BLOG_TITLE = ${BLOG_TITLE} # (translatable)
# This is the main URL for your site. It will be used
# in a prominent link
SITE_URL = ${SITE_URL}
@@ -18,37 +27,13 @@ SITE_URL = ${SITE_URL}
# If not set, defaults to SITE_URL
# BASE_URL = ${SITE_URL}
BLOG_EMAIL = ${BLOG_EMAIL}
-BLOG_DESCRIPTION = ${BLOG_DESCRIPTION}
+BLOG_DESCRIPTION = ${BLOG_DESCRIPTION} # (translatable)
# Nikola is multilingual!
#
# Currently supported languages are:
-# bg Bulgarian
-# ca Catalan
-# cs Czech [ALTERNATIVELY cz]
-# de German
-# el Greek [NOT gr!]
-# en English
-# eo Esperanto
-# es Spanish
-# et Estonian
-# eu Basque
-# fa Persian
-# fi Finnish
-# fr French
-# hi Hindi
-# hr Croatian
-# it Italian
-# ja Japanese [NOT jp!]
-# nb Norwegian Bokmål
-# nl Dutch
-# pt_br Portuguese (Brasil)
-# pl Polish
-# ru Russian
-# sl Slovenian [NOT sl_si!]
-# tr Turkish (Turkey) [NOT tr_tr!]
-# ur Urdu
-# zh_cn Chinese (Simplified)
+#
+${_SUPPORTED_LANGUAGES}
#
# If you want to use Nikola with a non-supported language you have to provide
# a module containing the necessary translations
@@ -62,40 +47,48 @@ DEFAULT_LANG = ${DEFAULT_LANG}
# What other languages do you have?
# The format is {"translationcode" : "path/to/translation" }
# the path will be used as a prefix for the generated pages location
-TRANSLATIONS = {
- DEFAULT_LANG: "",
- # Example for another language:
- # "es": "./es",
-}
+TRANSLATIONS = ${TRANSLATIONS}
# What will translated input files be named like?
-# If you have a page something.rst, then something.rst.pl will be considered
+# If you have a page something.rst, then something.pl.rst will be considered
# its Polish translation.
-# (in the above example: path == "something", lang == "pl", ext == "rst")
+# (in the above example: path == "something", ext == "rst", lang == "pl")
# this pattern is also used for metadata:
-# something.meta -> something.meta.pl
+# something.meta -> something.pl.meta
TRANSLATIONS_PATTERN = ${TRANSLATIONS_PATTERN}
-# If you don't want your Polish files to be considered Perl code, use this:
-# TRANSLATIONS_PATTERN = "{path}.{lang}.{ext}"
-# Note that this pattern will become the default in v7.0.0.
-
# Links for the sidebar / navigation bar.
# You should provide a key-value pair for each used language.
-NAVIGATION_LINKS = {
- DEFAULT_LANG: (
- ('/archive.html', 'Archives'),
- ('/categories/index.html', 'Tags'),
- ('/rss.xml', 'RSS'),
- ),
-}
+# (the same way you would do with a (translatable) setting.)
+NAVIGATION_LINKS = ${NAVIGATION_LINKS}
+
+# Name of the theme to use.
+THEME = ${THEME}
##############################################
# Below this point, everything is optional
##############################################
+# Post's dates are considered in UTC by default, if you want to use
+# another time zone, please set TIMEZONE to match. Check the available
+# list from Wikipedia:
+# http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+# (eg. 'Europe/Zurich')
+# Also, if you want to use a different time zone in some of your posts,
+# you can use the ISO 8601/RFC 3339 format (ex. 2012-03-30T23:00:00+02:00)
+TIMEZONE = ${TIMEZONE}
+
+# If you want to use ISO 8601 (also valid RFC 3339) throughout Nikola
+# (especially in new_post), set this to True.
+# Note that this does not affect DATE_FORMAT.
+# FORCE_ISO8601 = False
+
+# Date format used to display post dates.
+# (str used by datetime.datetime.strftime)
+# DATE_FORMAT = '%Y-%m-%d %H:%M'
+
# While nikola can select a sensible locale for each language,
# sometimes explicit control can come handy.
# In this file we express locales in the string form that
@@ -114,7 +107,7 @@ NAVIGATION_LINKS = {
#
# That fragment could have an associated metadata file (whatever/thing.meta),
# and optionally translated files (example for spanish, with code "es"):
-# whatever/thing.txt.es and whatever/thing.meta.es
+# whatever/thing.es.txt and whatever/thing.es.meta
#
# This assumes you use the default TRANSLATIONS_PATTERN.
#
@@ -154,11 +147,21 @@ COMPILERS = ${COMPILERS}
# Set to False for two-file posts, with separate metadata.
# ONE_FILE_POSTS = True
-# If this is set to True, then posts that are not translated to a language
-# LANG will not be visible at all in the pages in that language.
-# If set to False, the DEFAULT_LANG version will be displayed for
+# If this is set to True, the DEFAULT_LANG version will be displayed for
# untranslated posts.
-# HIDE_UNTRANSLATED_POSTS = False
+# If this is set to False, then posts that are not translated to a language
+# LANG will not be visible at all in the pages in that language.
+# Formerly known as HIDE_UNTRANSLATED_POSTS (inverse)
+# SHOW_UNTRANSLATED_POSTS = True
+
+# Nikola supports logo display. If you have one, you can put the URL here.
+# Final output is <img src="LOGO_URL" id="logo" alt="BLOG_TITLE">.
+# The URL may be relative to the site root.
+# LOGO_URL = ''
+
+# If you want to hide the title of your website (for example, if your logo
+# already contains the text), set this to False.
+# SHOW_BLOG_TITLE = True
# Paths for different autogenerated bits. These are combined with the
# translation paths.
@@ -171,7 +174,7 @@ COMPILERS = ${COMPILERS}
# If TAG_PAGES_ARE_INDEXES is set to True, each tag's page will contain
# the posts themselves. If set to False, it will be just a list of links.
-# TAG_PAGES_ARE_INDEXES = True
+# TAG_PAGES_ARE_INDEXES = False
# Final location for the main blog page and sibling paginated pages is
# output / TRANSLATION[lang] / INDEX_PATH / index-*.html
@@ -212,7 +215,7 @@ COMPILERS = ${COMPILERS}
# relative URL.
#
# If you don't need any of these, just set to []
-# REDIRECTIONS = ${REDIRECTIONS}
+REDIRECTIONS = ${REDIRECTIONS}
# Commands to execute to deploy. Can be anything, for example,
# you may use rsync:
@@ -222,6 +225,14 @@ COMPILERS = ${COMPILERS}
# To do manual deployment, set it to []
# DEPLOY_COMMANDS = []
+# For user.github.io/organization.github.io pages, the DEPLOY branch
+# MUST be 'master', and 'gh-pages' for other repositories.
+# GITHUB_SOURCE_BRANCH = 'master'
+# GITHUB_DEPLOY_BRANCH = 'gh-pages'
+
+# The name of the remote where you wish to push to, using github_deploy.
+# GITHUB_REMOTE_NAME = 'origin'
+
# Where the output site should be located
# If you don't use an absolute path, it will be considered as relative
# to the location of conf.py
@@ -308,10 +319,7 @@ COMPILERS = ${COMPILERS}
# INDEXES_TITLE = "" # If this is empty, defaults to BLOG_TITLE
# INDEXES_PAGES = "" # If this is empty, defaults to '[old posts,] page %d' (see above)
# INDEXES_PAGES_MAIN = False # If True, INDEXES_PAGES is also displayed on
- # the main (the newest) index page (index.html)
-
-# Name of the theme to use.
-THEME = ${THEME}
+# # the main (the newest) index page (index.html)
# Color scheme to be used for code blocks. If your theme provides
# "assets/css/code.css" this is ignored.
@@ -328,15 +336,9 @@ THEME = ${THEME}
# THEME_REVEAL_CONFIG_TRANSITION = 'cube'
# You can also use: page/concave/linear/none/default
-# date format used to display post dates.
-# (str used by datetime.datetime.strftime)
-# DATE_FORMAT = '%Y-%m-%d %H:%M'
-
# FAVICONS contains (name, file, size) tuples.
# Used for create favicon link like this:
# <link rel="name" href="file" sizes="size"/>
-# For creating favicons, take a look at:
-# http://www.netmagazine.com/features/create-perfect-favicon
# FAVICONS = {
# ("icon", "/favicon.ico", "16x16"),
# ("icon", "/icon_128x128.png", "128x128"),
@@ -345,15 +347,25 @@ THEME = ${THEME}
# Show only teasers in the index pages? Defaults to False.
# INDEX_TEASERS = False
-# A HTML fragment with the Read more... link.
+# HTML fragments with the Read more... links.
# The following tags exist and are replaced for you:
-# {link} A link to the full post page.
-# {read_more} The string “Read more” in the current language.
-# {{ A literal { (U+007B LEFT CURLY BRACKET)
-# }} A literal } (U+007D RIGHT CURLY BRACKET)
-# READ_MORE_LINK = '<p class="more"><a href="{link}">{read_more}…</a></p>'
+# {link} A link to the full post page.
+# {read_more} The string “Read more” in the current language.
+# {reading_time} An estimate of how long it will take to read the post.
+# {remaining_reading_time} An estimate of how long it will take to read the post, sans the teaser.
+# {min_remaining_read} The string “{remaining_reading_time} min remaining to read” in the current language.
+# {paragraph_count} The amount of paragraphs in the post.
+# {remaining_paragraph_count} The amount of paragraphs in the post, sans the teaser.
+# {{ A literal { (U+007B LEFT CURLY BRACKET)
+# }} A literal } (U+007D RIGHT CURLY BRACKET)
+
+# 'Read more...' for the index page, if INDEX_TEASERS is True (translatable)
+INDEX_READ_MORE_LINK = ${INDEX_READ_MORE_LINK}
+# 'Read more...' for the RSS_FEED, if RSS_TEASERS is True (translatable)
+RSS_READ_MORE_LINK = ${RSS_READ_MORE_LINK}
# A HTML fragment describing the license, for the sidebar.
+# (translatable)
LICENSE = ""
# I recommend using the Creative Commons' wizard:
# http://creativecommons.org/choose/
@@ -364,24 +376,45 @@ LICENSE = ""
# src="http://i.creativecommons.org/l/by-nc-sa/2.5/ar/88x31.png"></a>"""
# A small copyright notice for the page footer (in HTML).
+# (translatable)
CONTENT_FOOTER = 'Contents &copy; {date} \
<a href="mailto:{email}">{author}</a> - Powered by \
<a href="http://getnikola.com" rel="nofollow">Nikola</a> \
{license}'
-CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
- author=BLOG_AUTHOR,
- date=time.gmtime().tm_year,
- license=LICENSE)
+
+# Things that will be passed to CONTENT_FOOTER.format(). This is done
+# for translatability, as dicts are not formattable. Nikola will
+# intelligently format the setting properly.
+# The setting takes a dict. The keys are languages. The values are
+# tuples of tuples of positional arguments and dicts of keyword arguments
+# to format(). For example, {'en': (('Hello'), {'target': 'World'})}
+# results in CONTENT_FOOTER['en'].format('Hello', target='World').
+# WARNING: If you do not use multiple languages with CONTENT_FOOTER, this
+# still needs to be a dict of this format. (it can be empty if you
+# do not need formatting)
+# (translatable)
+CONTENT_FOOTER_FORMATS = {
+ DEFAULT_LANG: (
+ (),
+ {
+ "email": BLOG_EMAIL,
+ "author": BLOG_AUTHOR,
+ "date": time.gmtime().tm_year,
+ "license": LICENSE
+ }
+ )
+}
# To use comments, you can choose between different third party comment
-# systems, one of "disqus", "livefyre", "intensedebate", "moot",
-# "googleplus", "facebook" or "isso"
-# COMMENT_SYSTEM = ${COMMENT_SYSTEM}
+# systems. The following comment systems are supported by Nikola:
+${_SUPPORTED_COMMENT_SYSTEMS}
+# You can leave this option blank to disable comments.
+COMMENT_SYSTEM = ${COMMENT_SYSTEM}
# And you also need to add your COMMENT_SYSTEM_ID which
# depends on what comment system you use. The default is
# "nikolademo" which is a test account for Disqus. More information
# is in the manual.
-# COMMENT_SYSTEM_ID = ${COMMENT_SYSTEM_ID}
+COMMENT_SYSTEM_ID = ${COMMENT_SYSTEM_ID}
# Enable annotations using annotateit.org?
# If set to False, you can still enable them for individual posts and pages
@@ -418,6 +451,12 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# if /2012 includes any files (including index.html)... add it to the sitemap
# SITEMAP_INCLUDE_FILELESS_DIRS = True
+# List of files relative to the server root (!) that will be asked to be excluded
+# from indexing and other robotic spidering. * is supported. Will only be effective
+# if SITE_URL points to server root. The list is used to exclude resources from
+# /robots.txt and /sitemap.xml, and to inform search engines about /sitemapindex.xml.
+# ROBOTS_EXCLUSIONS = ["/archive.html", "/category/*.html"]
+
# Instead of putting files in <slug>.html, put them in
# <slug>/index.html. Also enables STRIP_INDEXES
# This can be disabled on a per-page/post basis by adding
@@ -441,27 +480,25 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# SCHEDULE_RULE = ''
# If True, use the scheduling rule to all posts by default
# SCHEDULE_ALL = False
-# If True, schedules post to today if possible, even if scheduled hour is over
-# SCHEDULE_FORCE_TODAY = False
# Do you want a add a Mathjax config file?
# MATHJAX_CONFIG = ""
# If you are using the compile-ipynb plugin, just add this one:
-#MATHJAX_CONFIG = """
-#<script type="text/x-mathjax-config">
-#MathJax.Hub.Config({
-# tex2jax: {
-# inlineMath: [ ['$','$'], ["\\\(","\\\)"] ],
-# displayMath: [ ['$$','$$'], ["\\\[","\\\]"] ]
-# },
-# displayAlign: 'left', // Change this to 'center' to center equations.
-# "HTML-CSS": {
-# styles: {'.MathJax_Display': {"margin": 0}}
-# }
-#});
-#</script>
-#"""
+# MATHJAX_CONFIG = """
+# <script type="text/x-mathjax-config">
+# MathJax.Hub.Config({
+# tex2jax: {
+# inlineMath: [ ['$','$'], ["\\\(","\\\)"] ],
+# displayMath: [ ['$$','$$'], ["\\\[","\\\]"] ]
+# },
+# displayAlign: 'left', // Change this to 'center' to center equations.
+# "HTML-CSS": {
+# styles: {'.MathJax_Display': {"margin": 0}}
+# }
+# });
+# </script>
+# """
# Do you want to customize the nbconversion of your IPython notebook?
# IPYNB_CONFIG = {}
@@ -469,13 +506,16 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# called `toggle.tpl` which has to be located in your site/blog main folder:
# IPYNB_CONFIG = {'Exporter':{'template_file': 'toggle'}}
-# What MarkDown extensions to enable?
+# What Markdown extensions to enable?
# You will also get gist, nikola and podcast because those are
# done in the code, hope you don't mind ;-)
+# Note: most Nikola-specific extensions are done via the Nikola plugin system,
+# with the MarkdownExtension class and should not be added here.
# MARKDOWN_EXTENSIONS = ['fenced_code', 'codehilite']
# Social buttons. This is sample code for AddThis (which was the default for a
# long time). Insert anything you want here, or even make it empty.
+# (translatable)
# SOCIAL_BUTTONS_CODE = """
# <!-- Social buttons -->
# <div id="addthisbox" class="addthis_toolbox addthis_peekaboo_style addthis_default_style addthis_label_style addthis_32x32_style">
@@ -486,20 +526,25 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# <li><a class="addthis_button_twitter"></a>
# </ul>
# </div>
-# <script type="text/javascript" src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script>
+# <script src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script>
# <!-- End of social buttons -->
# """
-# Hide link to source for the posts?
-# HIDE_SOURCELINK = False
+# Show link to source for the posts?
+# Formerly known as HIDE_SOURCELINK (inverse)
+# SHOW_SOURCELINK = True
# Copy the source files for your pages?
-# Setting it to False implies HIDE_SOURCELINK = True
+# Setting it to False implies SHOW_SOURCELINK = False
# COPY_SOURCES = True
# Modify the number of Post per Index Page
# Defaults to 10
# INDEX_DISPLAY_POST_COUNT = 10
+# By default, Nikola generates RSS files for the website and for tags, and
+# links to it. Set this to False to disable everything RSS-related.
+# GENERATE_RSS = True
+
# RSS_LINK is a HTML fragment to link the RSS or Atom feeds. If set to None,
# the base.tmpl will use the feed Nikola generates. However, you may want to
# change it for a feedburner feed or something else.
@@ -508,83 +553,59 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# Show only teasers in the RSS feed? Default to True
# RSS_TEASERS = True
+# Strip HTML in the RSS feed? Default to False
+# RSS_PLAIN = False
+
# A search form to search this site, for the sidebar. You can use a google
# custom search (http://www.google.com/cse/)
# Or a duckduckgo search: https://duckduckgo.com/search_box.html
# Default is no search form.
+# (translatable)
# SEARCH_FORM = ""
#
# This search form works for any site and looks good in the "site" theme where
# it appears on the navigation bar:
#
-#SEARCH_FORM = """
-#<!-- Custom search -->
-#<form method="get" id="search" action="http://duckduckgo.com/"
-# class="navbar-form pull-left">
-#<input type="hidden" name="sites" value="%s"/>
-#<input type="hidden" name="k8" value="#444444"/>
-#<input type="hidden" name="k9" value="#D51920"/>
-#<input type="hidden" name="kt" value="h"/>
-#<input type="text" name="q" maxlength="255"
-# placeholder="Search&hellip;" class="span2" style="margin-top: 4px;"/>
-#<input type="submit" value="DuckDuckGo Search" style="visibility: hidden;" />
-#</form>
-#<!-- End of custom search -->
-#""" % SITE_URL
+# SEARCH_FORM = """
+# <!-- Custom search -->
+# <form method="get" id="search" action="//duckduckgo.com/"
+# class="navbar-form pull-left">
+# <input type="hidden" name="sites" value="%s"/>
+# <input type="hidden" name="k8" value="#444444"/>
+# <input type="hidden" name="k9" value="#D51920"/>
+# <input type="hidden" name="kt" value="h"/>
+# <input type="text" name="q" maxlength="255"
+# placeholder="Search&hellip;" class="span2" style="margin-top: 4px;"/>
+# <input type="submit" value="DuckDuckGo Search" style="visibility: hidden;" />
+# </form>
+# <!-- End of custom search -->
+# """ % SITE_URL
#
# If you prefer a google search form, here's an example that should just work:
-#SEARCH_FORM = """
-#<!-- Custom search with google-->
-#<form id="search" action="http://google.com/search" method="get" class="navbar-form pull-left">
-#<input type="hidden" name="q" value="site:%s" />
-#<input type="text" name="q" maxlength="255" results="0" placeholder="Search"/>
-#</form>
-#<!-- End of custom search -->
-#""" % SITE_URL
-
-# Also, there is a local search plugin you can use, based on Tipue, but it requires setting several
-# options:
-
# SEARCH_FORM = """
-# <span class="navbar-form pull-left">
-# <input type="text" id="tipue_search_input">
-# </span>"""
-#
-# BODY_END = """
-# <script type="text/javascript" src="/assets/js/tipuesearch_set.js"></script>
-# <script type="text/javascript" src="/assets/js/tipuesearch.js"></script>
-# <script type="text/javascript">
-# $(document).ready(function() {
- # $('#tipue_search_input').tipuesearch({
- # 'mode': 'json',
- # 'contentLocation': '/assets/js/tipuesearch_content.json',
- # 'showUrl': false
- # });
-# });
-# </script>
-# """
-
-# EXTRA_HEAD_DATA = """
-# <link rel="stylesheet" type="text/css" href="/assets/css/tipuesearch.css">
-# <div id="tipue_search_content" style="margin-left: auto; margin-right: auto; padding: 20px;"></div>
-# """
-# ENABLED_EXTRAS = ['local_search']
-#
-###### End of local search example
-
+# <!-- Custom search with google-->
+# <form id="search" action="//www.google.com/search" method="get" class="navbar-form pull-left">
+# <input type="hidden" name="q" value="site:%s" />
+# <input type="text" name="q" maxlength="255" results="0" placeholder="Search"/>
+# </form>
+# <!-- End of custom search -->
+#""" % SITE_URL
-# Use content distribution networks for jquery and twitter-bootstrap css and js
-# If this is True, jquery is served from the Google CDN and twitter-bootstrap
-# is served from the NetDNA CDN
+# Use content distribution networks for jquery, twitter-bootstrap css and js,
+# and html5shiv (for older versions of Internet Explorer)
+# If this is True, jquery and html5shiv is served from the Google and twitter-
+# bootstrap is served from the NetDNA CDN
# Set this to False if you want to host your site without requiring access to
# external resources.
# USE_CDN = False
# Extra things you want in the pages HEAD tag. This will be added right
# before </head>
+# (translatable)
# EXTRA_HEAD_DATA = ""
# Google Analytics or whatever else you use. Added to the bottom of <body>
# in the default template (base.tmpl).
+# (translatable)
# BODY_END = ""
# The possibility to extract metadata from the filename by using a
@@ -602,12 +623,21 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# '(?P<date>\d{4}-\d{2}-\d{2})-(?P<slug>.*)-(?P<title>.*)\.md'
# FILE_METADATA_REGEXP = None
+# If you hate "Filenames with Capital Letters and Spaces.md", you should
+# set this to true.
+UNSLUGIFY_TITLES = True
+
# Additional metadata that is added to a post when creating a new_post
# ADDITIONAL_METADATA = {}
-# Nikola supports Twitter Card summaries / Open Graph.
-# Twitter cards make it possible for you to attach media to Tweets
-# that link to your content.
+# Nikola supports Open Graph Protocol data for enhancing link sharing and
+# discoverability of your site on Facebook, Google+, and other services.
+# Open Graph is enabled by default.
+# USE_OPEN_GRAPH = True
+
+# Nikola supports Twitter Card summaries
+# Twitter cards are disabled by default. They make it possible for you to
+# attach media to Tweets that link to your content.
#
# IMPORTANT:
# Please note, that you need to opt-in for using Twitter Cards!
@@ -619,7 +649,7 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# over the cleartext username. Specifying an ID is not necessary.
# Displaying images is currently not supported.
# TWITTER_CARD = {
-# # 'use_twitter_cards': True, # enable Twitter Cards / Open Graph
+# # 'use_twitter_cards': True, # enable Twitter Cards
# # 'site': '@website', # twitter nick for the website
# # 'site:id': 123456, # Same as site, but the website's Twitter user ID
# # instead.
@@ -627,17 +657,6 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# # 'creator:id': 654321, # Same as creator, but the Twitter user's ID.
# }
-
-# Post's dates are considered in UTC by default, if you want to use
-# another time zone, please set TIMEZONE to match. Check the available
-# list from Wikipedia:
-# http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
-# (eg. 'Europe/Zurich')
-# Also, if you want to use a different time zone in some of your posts,
-# you can use W3C-DTF Format (ex. 2012-03-30T23:00:00+02:00)
-#
-# TIMEZONE = 'UTC'
-
# If webassets is installed, bundle JS and CSS to make site loading faster
# USE_BUNDLES = True
@@ -649,16 +668,6 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# repository.
# EXTRA_PLUGINS_DIRS = []
-# Experimental plugins - use at your own risk.
-# They probably need some manual adjustments - please see their respective
-# readme.
-# ENABLED_EXTRAS = [
-# 'planetoid',
-# 'ipynb',
-# 'local_search',
-# 'render_mustache',
-# ]
-
# List of regular expressions, links matching them will always be considered
# valid by "nikola check -l"
# LINK_CHECK_WHITELIST = []
@@ -675,18 +684,23 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# DEMOTE_HEADERS = 1
# You can configure the logging handlers installed as plugins or change the
-# log level of the default stdout handler.
+# log level of the default stderr handler.
+# WARNING: The stderr handler allows only the loglevels of 'INFO' and 'DEBUG'.
+# This is done for safety reasons, as blocking out anything other
+# than 'DEBUG' may hide important information and break the user
+# experience!
+
LOGGING_HANDLERS = {
- 'stderr': {'loglevel': 'WARNING', 'bubble': True},
- #'smtp': {
- # 'from_addr': 'test-errors@example.com',
- # 'recipients': ('test@example.com'),
- # 'credentials':('testusername', 'password'),
- # 'server_addr': ('127.0.0.1', 25),
- # 'secure': (),
- # 'level': 'DEBUG',
- # 'bubble': True
- #}
+ 'stderr': {'loglevel': 'INFO', 'bubble': True},
+ # 'smtp': {
+ # 'from_addr': 'test-errors@example.com',
+ # 'recipients': ('test@example.com'),
+ # 'credentials':('testusername', 'password'),
+ # 'server_addr': ('127.0.0.1', 25),
+ # 'secure': (),
+ # 'level': 'DEBUG',
+ # 'bubble': True
+ # }
}
# Templates will use those filters, along with the defaults.
diff --git a/nikola/data/samplesite/galleries/demo/tesla2_lg.jpg b/nikola/data/samplesite/galleries/demo/tesla2_lg.jpg
index 8be0531..43ea5db 100644
--- a/nikola/data/samplesite/galleries/demo/tesla2_lg.jpg
+++ b/nikola/data/samplesite/galleries/demo/tesla2_lg.jpg
Binary files differ
diff --git a/nikola/data/samplesite/galleries/demo/tesla4_lg.jpg b/nikola/data/samplesite/galleries/demo/tesla4_lg.jpg
index e350491..9274950 100644
--- a/nikola/data/samplesite/galleries/demo/tesla4_lg.jpg
+++ b/nikola/data/samplesite/galleries/demo/tesla4_lg.jpg
Binary files differ
diff --git a/nikola/data/samplesite/galleries/demo/tesla_conducts_lg.jpg b/nikola/data/samplesite/galleries/demo/tesla_conducts_lg.jpg
index 7549d09..f47d2ae 100644
--- a/nikola/data/samplesite/galleries/demo/tesla_conducts_lg.jpg
+++ b/nikola/data/samplesite/galleries/demo/tesla_conducts_lg.jpg
Binary files differ
diff --git a/nikola/data/samplesite/galleries/demo/tesla_lightning1_lg.jpg b/nikola/data/samplesite/galleries/demo/tesla_lightning1_lg.jpg
index 7e4a6a0..3c12b0e 100644
--- a/nikola/data/samplesite/galleries/demo/tesla_lightning1_lg.jpg
+++ b/nikola/data/samplesite/galleries/demo/tesla_lightning1_lg.jpg
Binary files differ
diff --git a/nikola/data/samplesite/galleries/demo/tesla_lightning2_lg.jpg b/nikola/data/samplesite/galleries/demo/tesla_lightning2_lg.jpg
index 730b4de..8355d86 100644
--- a/nikola/data/samplesite/galleries/demo/tesla_lightning2_lg.jpg
+++ b/nikola/data/samplesite/galleries/demo/tesla_lightning2_lg.jpg
Binary files differ
diff --git a/nikola/data/samplesite/galleries/demo/tesla_tower1_lg.jpg b/nikola/data/samplesite/galleries/demo/tesla_tower1_lg.jpg
index 1b9edcb..7d8b95b 100644
--- a/nikola/data/samplesite/galleries/demo/tesla_tower1_lg.jpg
+++ b/nikola/data/samplesite/galleries/demo/tesla_tower1_lg.jpg
Binary files differ
diff --git a/nikola/data/samplesite/posts/1.rst b/nikola/data/samplesite/posts/1.rst
index 25e56f8..7116a7a 100644
--- a/nikola/data/samplesite/posts/1.rst
+++ b/nikola/data/samplesite/posts/1.rst
@@ -1,7 +1,8 @@
.. title: Welcome to Nikola
.. slug: welcome-to-nikola
-.. date: 2012/03/30 23:00
+.. date: 2012-03-30 23:00:00 UTC-03:00
.. tags: nikola, python, demo, blog
+.. author: Roberto Alsina
.. link: http://getnikola.com
.. description:
diff --git a/nikola/data/samplesite/stories/1.rst b/nikola/data/samplesite/stories/1.rst
index 27c75d8..b662fae 100644
--- a/nikola/data/samplesite/stories/1.rst
+++ b/nikola/data/samplesite/stories/1.rst
@@ -1,6 +1,6 @@
.. title: Nikola: it generates static
.. slug: about-nikola
-.. date: 2012/03/30 23:00
+.. date: 2012-03-30 23:00:00 UTC-03:00
.. tags:
.. link:
.. description:
diff --git a/nikola/data/samplesite/stories/a-study-in-scarlet.txt b/nikola/data/samplesite/stories/a-study-in-scarlet.txt
index 10f9528..2dfee52 100644
--- a/nikola/data/samplesite/stories/a-study-in-scarlet.txt
+++ b/nikola/data/samplesite/stories/a-study-in-scarlet.txt
@@ -1,7 +1,7 @@
.. link:
.. description:
.. tags:
-.. date: 2013/08/27 18:20:55
+.. date: 2013-08-27 18:20:55 UTC-03:00
.. title: A STUDY IN SCARLET.
.. slug: a-study-in-scarlet
diff --git a/nikola/data/samplesite/stories/bootstrap-demo.rst b/nikola/data/samplesite/stories/bootstrap-demo.rst
index 520e4b0..a7be1a9 100644
--- a/nikola/data/samplesite/stories/bootstrap-demo.rst
+++ b/nikola/data/samplesite/stories/bootstrap-demo.rst
@@ -1,6 +1,6 @@
.. title: Bootstrap Demo
.. slug: bootstrap-demo
-.. date: 2012/03/30 23:00
+.. date: 2012-03-30 23:00:00 UTC-03:00
.. tags: bootstrap, demo
.. link: http://getnikola.com
.. description:
diff --git a/nikola/data/samplesite/stories/charts.txt b/nikola/data/samplesite/stories/charts.txt
index 2c90fdf..72fedb1 100644
--- a/nikola/data/samplesite/stories/charts.txt
+++ b/nikola/data/samplesite/stories/charts.txt
@@ -1,7 +1,7 @@
.. link:
.. description:
.. tags:
-.. date: 2013/08/27 18:20:55
+.. date: 2013-08-27 18:20:55 UTC-03:00
.. title: Charts
.. slug: charts
diff --git a/nikola/data/samplesite/stories/listings-demo.rst b/nikola/data/samplesite/stories/listings-demo.rst
index 7875f17..3bb8dc6 100644
--- a/nikola/data/samplesite/stories/listings-demo.rst
+++ b/nikola/data/samplesite/stories/listings-demo.rst
@@ -1,6 +1,6 @@
.. title: Listings Demo
.. slug: listings-demo
-.. date: 2012/12/15 10:16:20
+.. date: 2012-12-15 10:16:20 UTC-03:00
.. tags:
.. link:
.. description:
diff --git a/nikola/data/samplesite/stories/quickref.rst b/nikola/data/samplesite/stories/quickref.rst
index 52e786f..7886cd1 100644
--- a/nikola/data/samplesite/stories/quickref.rst
+++ b/nikola/data/samplesite/stories/quickref.rst
@@ -1,6 +1,6 @@
.. title: A reStructuredText Reference
.. slug: quickref
-.. date: 2012/03/30 23:00
+.. date: 2012-03-30 23:00:00 UTC-03:00
.. tags:
.. link:
.. description:
diff --git a/nikola/data/samplesite/stories/quickstart.rst b/nikola/data/samplesite/stories/quickstart.rst
index 4282b23..5b78807 100644
--- a/nikola/data/samplesite/stories/quickstart.rst
+++ b/nikola/data/samplesite/stories/quickstart.rst
@@ -1,6 +1,6 @@
.. title: A reStructuredText Primer
.. slug: quickstart
-.. date: 2012/03/30 23:00
+.. date: 2012-03-30 23:00:00 UTC-03:00
.. tags:
.. link:
.. description:
diff --git a/nikola/data/samplesite/stories/slides-demo.rst b/nikola/data/samplesite/stories/slides-demo.rst
index fb1356b..0d07bbc 100644
--- a/nikola/data/samplesite/stories/slides-demo.rst
+++ b/nikola/data/samplesite/stories/slides-demo.rst
@@ -1,6 +1,6 @@
.. title: Slides Demo
.. slug: slides-demo
-.. date: 2012/12/27 10:16:20
+.. date: 2012-12-27 10:16:20 UTC-03:00
.. tags:
.. link:
.. description:
diff --git a/nikola/data/symlinked.txt b/nikola/data/symlinked.txt
new file mode 100644
index 0000000..5a08781
--- /dev/null
+++ b/nikola/data/symlinked.txt
@@ -0,0 +1,151 @@
+docs/sphinx/creating-a-site.txt
+docs/sphinx/creating-a-theme.txt
+docs/sphinx/extending.txt
+docs/sphinx/internals.txt
+docs/sphinx/manual.txt
+docs/sphinx/social_buttons.txt
+docs/sphinx/theming.txt
+docs/sphinx/upgrading-to-v6.txt
+nikola/data/samplesite/stories/creating-a-theme.rst
+nikola/data/samplesite/stories/extending.txt
+nikola/data/samplesite/stories/internals.txt
+nikola/data/samplesite/stories/manual.rst
+nikola/data/samplesite/stories/social_buttons.txt
+nikola/data/samplesite/stories/theming.rst
+nikola/data/samplesite/stories/upgrading-to-v6.txt
+nikola/data/themes/base/messages/messages_cz.py
+nikola/data/themes/bootstrap-jinja/assets/css/bootstrap-responsive.css
+nikola/data/themes/bootstrap-jinja/assets/css/bootstrap-responsive.min.css
+nikola/data/themes/bootstrap-jinja/assets/css/bootstrap.css
+nikola/data/themes/bootstrap-jinja/assets/css/bootstrap.min.css
+nikola/data/themes/bootstrap-jinja/assets/css/colorbox.css
+nikola/data/themes/bootstrap-jinja/assets/css/images/controls.png
+nikola/data/themes/bootstrap-jinja/assets/css/images/loading.gif
+nikola/data/themes/bootstrap-jinja/assets/css/theme.css
+nikola/data/themes/bootstrap-jinja/assets/img/glyphicons-halflings-white.png
+nikola/data/themes/bootstrap-jinja/assets/img/glyphicons-halflings.png
+nikola/data/themes/bootstrap-jinja/assets/js/bootstrap.js
+nikola/data/themes/bootstrap-jinja/assets/js/bootstrap.min.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ar.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-bg.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ca.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-cs.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-da.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-de.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-es.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-et.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fa.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fi.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fr.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-gl.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-gr.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-he.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-hr.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-hu.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-id.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-it.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ja.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-kr.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-lt.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-lv.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-my.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-nl.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-no.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-pl.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-pt-br.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ro.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ru.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-si.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sk.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sr.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sv.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-tr.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-uk.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-zh-CN.js
+nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-zh-TW.js
+nikola/data/themes/bootstrap-jinja/assets/js/flowr.plugin.js
+nikola/data/themes/bootstrap-jinja/assets/js/jquery.colorbox-min.js
+nikola/data/themes/bootstrap-jinja/assets/js/jquery.colorbox.js
+nikola/data/themes/bootstrap-jinja/assets/js/jquery.min.js
+nikola/data/themes/bootstrap-jinja/assets/js/jquery.min.map
+nikola/data/themes/bootstrap-jinja/bundles
+nikola/data/themes/bootstrap/assets/css/colorbox.css
+nikola/data/themes/bootstrap/assets/css/images/controls.png
+nikola/data/themes/bootstrap/assets/css/images/loading.gif
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ar.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-bg.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ca.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-cs.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-da.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-de.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-es.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-et.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fa.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fi.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fr.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-gl.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-gr.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-he.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-hr.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-hu.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-id.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-it.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ja.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-kr.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-lt.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-lv.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-my.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-nl.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-no.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-pl.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-pt-br.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ro.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ru.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-si.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sk.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sr.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sv.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-tr.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-uk.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-zh-CN.js
+nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-zh-TW.js
+nikola/data/themes/bootstrap/assets/js/jquery.colorbox-min.js
+nikola/data/themes/bootstrap/assets/js/jquery.colorbox.js
+nikola/data/themes/bootstrap/assets/js/jquery.min.js
+nikola/data/themes/bootstrap/assets/js/jquery.min.map
+nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.css
+nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.css.map
+nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.min.css
+nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.css
+nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.css.map
+nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.min.css
+nikola/data/themes/bootstrap3-jinja/assets/css/docs.css
+nikola/data/themes/bootstrap3-jinja/assets/css/images/ie6/borderBottomCenter.png
+nikola/data/themes/bootstrap3-jinja/assets/css/images/ie6/borderBottomLeft.png
+nikola/data/themes/bootstrap3-jinja/assets/css/images/ie6/borderBottomRight.png
+nikola/data/themes/bootstrap3-jinja/assets/css/images/ie6/borderMiddleLeft.png
+nikola/data/themes/bootstrap3-jinja/assets/css/images/ie6/borderMiddleRight.png
+nikola/data/themes/bootstrap3-jinja/assets/css/images/ie6/borderTopCenter.png
+nikola/data/themes/bootstrap3-jinja/assets/css/images/ie6/borderTopLeft.png
+nikola/data/themes/bootstrap3-jinja/assets/css/images/ie6/borderTopRight.png
+nikola/data/themes/bootstrap3-jinja/assets/css/rst.css
+nikola/data/themes/bootstrap3-jinja/assets/css/theme.css
+nikola/data/themes/bootstrap3-jinja/assets/fonts/glyphicons-halflings-regular.eot
+nikola/data/themes/bootstrap3-jinja/assets/fonts/glyphicons-halflings-regular.svg
+nikola/data/themes/bootstrap3-jinja/assets/fonts/glyphicons-halflings-regular.ttf
+nikola/data/themes/bootstrap3-jinja/assets/fonts/glyphicons-halflings-regular.woff
+nikola/data/themes/bootstrap3-jinja/assets/js/bootstrap.js
+nikola/data/themes/bootstrap3-jinja/assets/js/bootstrap.min.js
+nikola/data/themes/bootstrap3-jinja/bundles
+nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.css
+nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.css.map
+nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.min.css
+nikola/data/themes/bootstrap3/assets/css/bootstrap.css
+nikola/data/themes/bootstrap3/assets/css/bootstrap.css.map
+nikola/data/themes/bootstrap3/assets/css/bootstrap.min.css
+nikola/data/themes/bootstrap3/assets/fonts/glyphicons-halflings-regular.eot
+nikola/data/themes/bootstrap3/assets/fonts/glyphicons-halflings-regular.svg
+nikola/data/themes/bootstrap3/assets/fonts/glyphicons-halflings-regular.ttf
+nikola/data/themes/bootstrap3/assets/fonts/glyphicons-halflings-regular.woff
+nikola/data/themes/bootstrap3/assets/js/bootstrap.js
+nikola/data/themes/bootstrap3/assets/js/bootstrap.min.js
diff --git a/nikola/data/themes/base-jinja/AUTHORS.txt b/nikola/data/themes/base-jinja/AUTHORS.txt
new file mode 100644
index 0000000..043d497
--- /dev/null
+++ b/nikola/data/themes/base-jinja/AUTHORS.txt
@@ -0,0 +1 @@
+Roberto Alsina <https://github.com/ralsina>
diff --git a/nikola/data/themes/base-jinja/README.md b/nikola/data/themes/base-jinja/README.md
new file mode 100644
index 0000000..5d1da94
--- /dev/null
+++ b/nikola/data/themes/base-jinja/README.md
@@ -0,0 +1,4 @@
+This theme has almost no styling, it's meant as a basis from which other
+themes can be developed.
+
+Therefore, most "advanced" features, such as slides or galleries, are broken.
diff --git a/nikola/data/themes/base-jinja/bundles b/nikola/data/themes/base-jinja/bundles
new file mode 100644
index 0000000..4760181
--- /dev/null
+++ b/nikola/data/themes/base-jinja/bundles
@@ -0,0 +1,2 @@
+assets/css/all.css=rst.css,code.css,theme.css
+assets/css/all-nocdn.css=rst.css,code.css,theme.css
diff --git a/nikola/data/themes/base-jinja/engine b/nikola/data/themes/base-jinja/engine
new file mode 100644
index 0000000..6f04b30
--- /dev/null
+++ b/nikola/data/themes/base-jinja/engine
@@ -0,0 +1 @@
+jinja
diff --git a/nikola/data/themes/base-jinja/parent b/nikola/data/themes/base-jinja/parent
new file mode 100644
index 0000000..df967b9
--- /dev/null
+++ b/nikola/data/themes/base-jinja/parent
@@ -0,0 +1 @@
+base
diff --git a/nikola/data/themes/base-jinja/templates/annotation_helper.tmpl b/nikola/data/themes/base-jinja/templates/annotation_helper.tmpl
new file mode 100644
index 0000000..86d09b2
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/annotation_helper.tmpl
@@ -0,0 +1,16 @@
+{% macro css() %}
+ <link rel="stylesheet" href="http://assets.annotateit.org/annotator/v1.2.5/annotator.min.css">
+{% endmacro %}
+
+{% macro code() %}
+ <script src="http://code.jquery.com/jquery-migrate-1.2.1.js"></script>
+ <script src="http://assets.annotateit.org/annotator/v1.2.7/annotator-full.js"></script>
+ <script>
+ jQuery(function ($) {
+ $('body').annotator().annotator('setupPlugins', {}, {
+ // Disable filter bar
+ Filter: false
+ });
+ });
+ </script>
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/base.tmpl b/nikola/data/themes/base-jinja/templates/base.tmpl
new file mode 100644
index 0000000..2b15177
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/base.tmpl
@@ -0,0 +1,25 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'base_helper.tmpl' as base with context %}
+{% import 'base_header.tmpl' as header with context %}
+{% import 'base_footer.tmpl' as footer with context %}
+{% import 'annotation_helper.tmpl' as annotations with context %}
+{{ set_locale(lang) }}
+{{ base.html_headstart() }}
+{% block extra_head %}
+{# Leave this block alone. #}
+{% endblock %}
+{{ template_hooks['extra_head']() }}
+</head>
+<body>
+ <div id="container">
+ {{ header.html_header() }}
+ <main id="content">
+ {% block content %}{% endblock %}
+ </main>
+ {{ footer.html_footer() }}
+ </div>
+ {{ body_end }}
+ {{ template_hooks['body_end']() }}
+ {{ base.late_load_js() }}
+</body>
+</html>
diff --git a/nikola/data/themes/base-jinja/templates/base_footer.tmpl b/nikola/data/themes/base-jinja/templates/base_footer.tmpl
new file mode 100644
index 0000000..7fcf616
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/base_footer.tmpl
@@ -0,0 +1,11 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'base_helper.tmpl' as base with context %}
+
+{% macro html_footer() %}
+ {% if content_footer %}
+ <footer id="footer" role="contentinfo">
+ <p>{{ content_footer }}</p>
+ {{ template_hooks['page_footer']() }}
+ </footer>
+ {% endif %}
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/base_header.tmpl b/nikola/data/themes/base-jinja/templates/base_header.tmpl
new file mode 100644
index 0000000..1001db3
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/base_header.tmpl
@@ -0,0 +1,66 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'base_helper.tmpl' as base with context %}
+
+{% macro html_header() %}
+ <header id="header" role="banner">
+ {{ html_site_title() }}
+ {{ html_translation_header() }}
+ {{ html_navigation_links() }}
+ {% if search_form %}
+ <div class="searchform" role="search">
+ {{ search_form }}
+ </div>
+ {% endif %}
+ </header>
+ {{ template_hooks['page_header']() }}
+{% endmacro %}
+
+{% macro html_site_title() %}
+ <h1 id="brand"><a href="{{ abs_link('/') }}" title="{{ blog_title }}" rel="home">
+ {% if logo_url %}
+ <img src="{{ logo_url }}" alt="{{ blog_title }}" id="logo">
+ {% endif %}
+
+ {% if show_blog_title %}
+ <span id="blog-title">{{ blog_title }}</span>
+ {% endif %}
+ </a></h1>
+{% endmacro %}
+
+{% macro html_navigation_links() %}
+ <nav id="menu" role="navigation">
+ <ul>
+ {% for url, text in navigation_links[lang] %}
+ {% if url is mapping %}
+ <li> {{ text }}
+ <ul>
+ {% for suburl, text in url %}
+ {% if rel_link(permalink, suburl) == "#" %}
+ <li class="active"><a href="{{ permalink }}">{{ text }}</a></li>
+ {% else %}
+ <li><a href="{{ suburl }}">{{ text }}</a></li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ {% else %}
+ {% if rel_link(permalink, url) == "#" %}
+ <li class="active"><a href="{{ permalink }}">{{ text }}</a></li>
+ {% else %}
+ <li><a href="{{ url }}">{{ text }}</a></li>
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+ {{ template_hooks['menu']() }}
+ {{ template_hooks['menu_alt']() }}
+ </ul>
+ </nav>
+{% endmacro %}
+
+{% macro html_translation_header() %}
+ {% if translations|length > 1 %}
+ <div id="toptranslations">
+ <h2>{{ messages("Languages:") }}</h2>
+ {{ base.html_translations() }}
+ </div>
+ {% endif %}
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/base_helper.tmpl b/nikola/data/themes/base-jinja/templates/base_helper.tmpl
new file mode 100644
index 0000000..2dda87b
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/base_helper.tmpl
@@ -0,0 +1,103 @@
+{# -*- coding: utf-8 -*- #}
+
+{% macro html_headstart() %}
+<!DOCTYPE html>
+<html
+
+{% if use_open_graph or (twitter_card and twitter_card['use_twitter_cards']) or (comment_system == 'facebook') %}
+prefix='
+{% if use_open_graph or (twitter_card and twitter_card['use_twitter_cards']) %}
+og: http://ogp.me/ns#
+{% endif %}
+{% if use_open_graph %}
+article: http://ogp.me/ns/article#
+{% endif %}
+{% if comment_system == 'facebook' %}
+fb: http://ogp.me/ns/fb#
+{% endif %}
+'
+{% endif %}
+
+{% if is_rtl %}
+dir="rtl"
+{% endif %}
+
+lang="{{ lang }}">
+ <head>
+ <meta charset="utf-8">
+ {% if description %}
+ <meta name="description" content="{{ description }}">
+ {% endif %}
+ <meta name="viewport" content="width=device-width">
+ <title>{{ title|e }} | {{ blog_title|e }}</title>
+
+ {{ html_stylesheets() }}
+ {{ html_feedlinks() }}
+ {% if permalink %}
+ <link rel="canonical" href="{{ abs_link(permalink) }}">
+ {% endif %}
+
+ {% if favicons %}
+ {% for name, file, size in favicons %}
+ <link rel="{{ name }}" href="{{ file }}" sizes="{{ size }}"/>
+ {% endfor %}
+ {% endif %}
+
+ {% if comment_system == 'facebook' %}
+ <meta property="fb:app_id" content="{{ comment_system_id }}">
+ {% endif %}
+
+ {{ mathjax_config }}
+ {% if use_cdn %}
+ <!--[if lt IE 9]><script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
+ {% else %}
+ <!--[if lt IE 9]><script src="/assets/js/html5.js"></script><![endif]-->
+ {% endif %}
+
+ {{ extra_head_data }}
+{% endmacro %}
+
+{% macro late_load_js() %}
+ {{ social_buttons_code }}
+{% endmacro %}
+
+{% macro html_stylesheets() %}
+ {% if use_bundles %}
+ {% if use_cdn %}
+ <link href="/assets/css/all.css" rel="stylesheet" type="text/css">
+ {% else %}
+ <link href="/assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
+ {% endif %}
+ {% else %}
+ <link href="/assets/css/rst.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/code.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/theme.css" rel="stylesheet" type="text/css">
+ {% if has_custom_css %}
+ <link href="/assets/css/custom.css" rel="stylesheet" type="text/css">
+ {% endif %}
+ {% endif %}
+{% endmacro %}
+
+{% macro html_feedlinks() %}
+ {% if rss_link %}
+ {{ rss_link }}
+ {% elif generate_rss %}
+ {% if translations|length > 1 %}
+ {% for language in translations %}
+ <link rel="alternate" type="application/rss+xml" title="RSS ({{ language }})" href="{{ _link('rss', None, language) }}">
+ {% endfor %}
+ {% else %}
+ <link rel="alternate" type="application/rss+xml" title="RSS" href="{{ _link('rss', None) }}">
+ {% endif %}
+ {% endif %}
+{% endmacro %}
+
+{% macro html_translations() %}
+ <ul class="translations">
+ {% for langname in translations.keys() %}
+ {% if langname != lang %}
+ <li><a href="{{ _link("index", None, langname) }}" rel="alternate" hreflang="{{ langname }}">{{ messages("LANGUAGE", langname) }}</a></li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/comments_helper.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper.tmpl
new file mode 100644
index 0000000..aba7294
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/comments_helper.tmpl
@@ -0,0 +1,63 @@
+{# -*- coding: utf-8 -*- #}
+
+{% import 'comments_helper_disqus.tmpl' as disqus with context %}
+{% import 'comments_helper_livefyre.tmpl' as livefyre with context %}
+{% import 'comments_helper_intensedebate.tmpl' as intensedebate with context %}
+{% import 'comments_helper_muut.tmpl' as muut with context %}
+{% import 'comments_helper_googleplus.tmpl' as googleplus with context %}
+{% import 'comments_helper_facebook.tmpl' as facebook with context %}
+{% import 'comments_helper_isso.tmpl' as isso with context %}
+
+{% macro comment_form(url, title, identifier) %}
+ {% if comment_system == 'disqus' %}
+ {{ disqus.comment_form(url, title, identifier) }}
+ {% elif comment_system == 'livefyre' %}
+ {{ livefyre.comment_form(url, title, identifier) }}
+ {% elif comment_system == 'intensedebate' %}
+ {{ intensedebate.comment_form(url, title, identifier) }}
+ {% elif comment_system == 'muut' %}
+ {{ muut.comment_form(url, title, identifier) }}
+ {% elif comment_system == 'googleplus' %}
+ {{ googleplus.comment_form(url, title, identifier) }}
+ {% elif comment_system == 'facebook' %}
+ {{ facebook.comment_form(url, title, identifier) }}
+ {% elif comment_system == 'isso' %}
+ {{ isso.comment_form(url, title, identifier) }}
+ {% endif %}
+{% endmacro %}
+
+{% macro comment_link(link, identifier) %}
+ {% if comment_system == 'disqus' %}
+ {{ disqus.comment_link(link, identifier) }}
+ {% elif comment_system == 'livefyre' %}
+ {{ livefyre.comment_link(link, identifier) }}
+ {% elif comment_system == 'intensedebate' %}
+ {{ intensedebate.comment_link(link, identifier) }}
+ {% elif comment_system == 'muut' %}
+ {{ muut.comment_link(link, identifier) }}
+ {% elif comment_system == 'googleplus' %}
+ {{ googleplus.comment_link(link, identifier) }}
+ {% elif comment_system == 'facebook' %}
+ {{ facebook.comment_link(link, identifier) }}
+ {% elif comment_system == 'isso' %}
+ {{ isso.comment_link(link, identifier) }}
+ {% endif %}
+{% endmacro %}
+
+{% macro comment_link_script() %}
+ {% if comment_system == 'disqus' %}
+ {{ disqus.comment_link_script() }}
+ {% elif comment_system == 'livefyre' %}
+ {{ livefyre.comment_link_script() }}
+ {% elif comment_system == 'intensedebate' %}
+ {{ intensedebate.comment_link_script() }}
+ {% elif comment_system == 'muut' %}
+ {{ muut.comment_link_script() }}
+ {% elif comment_system == 'googleplus' %}
+ {{ googleplus.comment_link_script() }}
+ {% elif comment_system == 'facebook' %}
+ {{ facebook.comment_link_script() }}
+ {% elif comment_system == 'isso' %}
+ {{ isso.comment_link_script() }}
+ {% endif %}
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/comments_helper_disqus.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper_disqus.tmpl
new file mode 100644
index 0000000..8288bd4
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/comments_helper_disqus.tmpl
@@ -0,0 +1,44 @@
+{# -*- coding: utf-8 -*- #}
+<%!
+ import json
+ translations = {
+ 'es': 'es_ES',
+ }
+%>
+
+{% macro comment_form(url, title, identifier) %}
+ {% if comment_system_id %}
+ <div id="disqus_thread"></div>
+ <script>
+ var disqus_shortname ="{{ comment_system_id }}",
+ {% if url %}
+ disqus_url="{{ url }}",
+ {% endif %}
+ disqus_title={{ title|tojson }},
+ disqus_identifier="{{ identifier }}",
+ disqus_config = function () {
+ this.language = "{{ translations.get(lang, lang) }}";
+ };
+ (function() {
+ var dsq = document.createElement('script'); dsq.async = true;
+ dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
+ })();
+ </script>
+ <noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
+ <a href="//disqus.com" class="dsq-brlink" rel="nofollow">Comments powered by <span class="logo-disqus">Disqus</span></a>
+ {% endif %}
+{% endmacro %}
+
+{% macro comment_link(link, identifier) %}
+ {% if comment_system_id %}
+ <a href="{{ link }}#disqus_thread" data-disqus-identifier="{{ identifier }}">Comments</a>
+ {% endif %}
+{% endmacro %}
+
+
+{% macro comment_link_script() %}
+ {% if comment_system_id %}
+ <script>var disqus_shortname="{{ comment_system_id }}";(function(){var a=document.createElement("script");a.async=true;a.src="//"+disqus_shortname+".disqus.com/count.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a)}());</script>
+ {% endif %}
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/comments_helper_facebook.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper_facebook.tmpl
new file mode 100644
index 0000000..21dac2a
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/comments_helper_facebook.tmpl
@@ -0,0 +1,62 @@
+{# -*- coding: utf-8 -*- #}
+{% macro comment_form(url, title, identifier) %}
+<div id="fb-root"></div>
+<script>
+ window.fbAsyncInit = function() {
+ // init the FB JS SDK
+ FB.init({
+ appId : '{{ comment_system_id }}',
+ status : true,
+ xfbml : true
+ });
+
+ };
+
+ // Load the SDK asynchronously
+ (function(d, s, id){
+ var js, fjs = d.getElementsByTagName(s)[0];
+ if (d.getElementById(id)) {return;}
+ js = d.createElement(s); js.id = id;
+ js.src = "//connect.facebook.net/en_US/all.js";
+ fjs.parentNode.insertBefore(js, fjs);
+ }(document, 'script', 'facebook-jssdk'));
+</script>
+
+<div class="fb-comments" data-href="{{ url }}" data-width="470"></div>
+{% endmacro %}
+
+{% macro comment_link(link, identifier) %}
+<span class="fb-comments-count" data-url="{{ link }}">
+{% endmacro %}
+
+{% macro comment_link_script() %}
+<div id="fb-root"></div>
+<script>
+ // thank lxml for this
+ $('.fb-comments-count').each(function(i, obj) {
+ var url = obj.attributes['data-url'].value;
+ // change here if you dislike the default way of displaying
+ // this
+ obj.innerHTML = '<fb:comments-count href="' + url + '"></fb:comments-count> comments';
+ });
+
+ window.fbAsyncInit = function() {
+ // init the FB JS SDK
+ FB.init({
+ appId : '{{ comment_system_id }}',
+ status : true,
+ xfbml : true
+ });
+
+ };
+
+ // Load the SDK asynchronously
+ (function(d, s, id){
+ var js, fjs = d.getElementsByTagName(s)[0];
+ if (d.getElementById(id)) {return;}
+ js = d.createElement(s); js.id = id;
+ js.src = "//connect.facebook.net/en_US/all.js";
+ fjs.parentNode.insertBefore(js, fjs);
+ }(document, 'script', 'facebook-jssdk'));
+</script>
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/comments_helper_googleplus.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper_googleplus.tmpl
new file mode 100644
index 0000000..cf153e0
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/comments_helper_googleplus.tmpl
@@ -0,0 +1,17 @@
+{# -*- coding: utf-8 -*- #}
+{% macro comment_form(url, title, identifier) %}
+<script src="https://apis.google.com/js/plusone.js"></script>
+<div class="g-comments"
+ data-href="{{ url }}"
+ data-first_party_property="BLOGGER"
+ data-view_type="FILTERED_POSTMOD">
+</div>
+{% endmacro %}
+
+{% macro comment_link(link, identifier) %}
+<div class="g-commentcount" data-href="{{ link }}"></div>
+<script src="https://apis.google.com/js/plusone.js"></script>
+{% endmacro %}
+
+{% macro comment_link_script() %}
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/comments_helper_intensedebate.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper_intensedebate.tmpl
new file mode 100644
index 0000000..042409b
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/comments_helper_intensedebate.tmpl
@@ -0,0 +1,25 @@
+{# -*- coding: utf-8 -*- #}
+{% macro comment_form(url, title, identifier) %}
+<script>
+var idcomments_acct = '{{ comment_system_id }}';
+var idcomments_post_id = "{{ identifier }}";
+var idcomments_post_url = "{{ url }}";
+</script>
+<span id="IDCommentsPostTitle" style="display:none"></span>
+<script src='http://www.intensedebate.com/js/genericCommentWrapperV2.js'></script>
+</script>
+{% endmacro %}
+
+{% macro comment_link(link, identifier) %}
+<a href="{link}" onclick="this.href='{{ link }}'; this.target='_self';"><span class='IDCommentsReplace' style='display:none'>{{ identifier }}</span>
+<script>
+var idcomments_acct = '{{ comment_system_id }}';
+var idcomments_post_id = "{{ identifier }}";
+var idcomments_post_url = "{{ link }}";
+</script>
+<script src="http://www.intensedebate.com/js/genericLinkWrapperV2.js"></script>
+</a>
+{% endmacro %}
+
+{% macro comment_link_script() %}
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/comments_helper_isso.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper_isso.tmpl
new file mode 100644
index 0000000..22a9595
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/comments_helper_isso.tmpl
@@ -0,0 +1,20 @@
+{# -*- coding: utf-8 -*- #}
+{% macro comment_form(url, title, identifier) %}
+ {% if comment_system_id %}
+ <div data-title="{{ title|urlencode }}" id="isso-thread"></div>
+ <script src="{{ comment_system_id }}js/embed.min.js" data-isso="{{ comment_system_id }}"></script>
+ {% endif %}
+{% endmacro %}
+
+{% macro comment_link(link, identifier) %}
+ {% if comment_system_id %}
+ <a href="{{ link }}#isso-thread">Comments</a>
+ {% endif %}
+{% endmacro %}
+
+
+{% macro comment_link_script() %}
+ {% if comment_system_id %}
+ <script src="{{ comment_system_id }}js/count.min.js" data-isso="{{ comment_system_id }}"></script>
+ {% endif %}
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/comments_helper_livefyre.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper_livefyre.tmpl
new file mode 100644
index 0000000..5b01fbf
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/comments_helper_livefyre.tmpl
@@ -0,0 +1,33 @@
+{# -*- coding: utf-8 -*- #}
+{% macro comment_form(url, title, identifier) %}
+<div id="livefyre-comments"></div>
+<script src="http://zor.livefyre.com/wjs/v3.0/javascripts/livefyre.js"></script>
+<script>
+(function () {
+ var articleId = "{{ identifier }}";
+ fyre.conv.load({}, [{
+ el: 'livefyre-comments',
+ network: "livefyre.com",
+ siteId: "{{ comment_system_id }}",
+ articleId: articleId,
+ signed: false,
+ collectionMeta: {
+ articleId: articleId,
+ url: fyre.conv.load.makeCollectionUrl(),
+ }
+ }], function() {});
+}());
+</script>
+{% endmacro %}
+
+{% macro comment_link(link, identifier) %}
+ <a href="{{ link }}">
+ <span class="livefyre-commentcount" data-lf-site-id="{{ comment_system_id }}" data-lf-article-id="{{ identifier }}">
+ 0 Comments
+ </span>
+{% endmacro %}
+
+
+{% macro comment_link_script() %}
+<script src="http://zor.livefyre.com/wjs/v1.0/javascripts/CommentCount.js"></script>
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/comments_helper_mustache.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper_mustache.tmpl
new file mode 100644
index 0000000..8912e19
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/comments_helper_mustache.tmpl
@@ -0,0 +1,5 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'comments_helper.tmpl' as comments with context %}
+{% if not post.meta('nocomments') %}
+ {{ comments.comment_form(post.permalink(absolute=True), post.title(), post.base_path) }}
+{% endif %}
diff --git a/nikola/data/themes/base-jinja/templates/comments_helper_muut.tmpl b/nikola/data/themes/base-jinja/templates/comments_helper_muut.tmpl
new file mode 100644
index 0000000..79ae523
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/comments_helper_muut.tmpl
@@ -0,0 +1,13 @@
+{# -*- coding: utf-8 -*- #}
+
+{% macro comment_form(url, title, identifier) %}
+ <a class="muut" href="https://muut.com/i/{{ comment_system_id }}/{{ identifier }}">{{ comment_system_id }} forums</a>
+{% endmacro %}
+
+{% macro comment_link(link, identifier) %}
+{% endmacro %}
+
+
+{% macro comment_link_script() %}
+<script src="//cdn.muut.com/1/moot.min.js"></script>
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/crumbs.tmpl b/nikola/data/themes/base-jinja/templates/crumbs.tmpl
new file mode 100644
index 0000000..eede9c2
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/crumbs.tmpl
@@ -0,0 +1,13 @@
+{# -*- coding: utf-8 -*- #}
+
+{% macro bar(crumbs) %}
+{% if crumbs %}
+<nav class="breadcrumbs">
+<ul class="breadcrumb">
+ {% for link, text in crumbs %}
+ <li><a href="{{ link }}">{{ text }}</a></li>
+ {% endfor %}
+</ul>
+</nav>
+{% endif %}
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/gallery.tmpl b/nikola/data/themes/base-jinja/templates/gallery.tmpl
new file mode 100644
index 0000000..86eea12
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/gallery.tmpl
@@ -0,0 +1,36 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'base.tmpl' %}
+{% import 'comments_helper.tmpl' as comments with context %}
+{% import 'crumbs.tmpl' as ui with context %}
+{% block sourcelink %}{% endblock %}
+
+{% block content %}
+ {{ ui.bar(crumbs) }}
+ {% if title %}
+ <h1>{{ title }}</h1>
+ {% endif %}
+ {% if post %}
+ <p>
+ {{ post.text() }}
+ </p>
+ {% endif %}
+ {% if folders %}
+ <ul>
+ {% for folder, ftitle in folders %}
+ <li><a href="{{ folder }}"><i
+ class="icon-folder-open"></i>&nbsp;{{ ftitle }}</a></li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+ {% if photo_array %}
+ <ul class="thumbnails">
+ {% for image in photo_array %}
+ <li><a href="{{ image['url'] }}" class="thumbnail image-reference" title="{{ image['title'] }}">
+ <img src="{{ image['url_thumb'] }}" alt="{{ image['title'] }}" /></a>
+ {% endfor %}
+ </ul>
+ {% endif %}
+{% if site_has_comments and enable_comments %}
+ {{ comments.comment_form(None, permalink, title) }}
+{% endif %}
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/index.tmpl b/nikola/data/themes/base-jinja/templates/index.tmpl
new file mode 100644
index 0000000..206fc34
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/index.tmpl
@@ -0,0 +1,34 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'index_helper.tmpl' as helper with context %}
+{% import 'comments_helper.tmpl' as comments with context %}
+{% extends 'base.tmpl' %}
+
+{% block content %}
+<div class="postindex">
+{% for post in posts %}
+ <article class="h-entry post-{{ post.meta('type') }}">
+ <header>
+ <h1 class="p-name entry-title"><a href="{{ post.permalink() }}" class="u-url">{{ post.title() }}</h1></a>
+ <div class="metadata">
+ <p class="byline author vcard"><span class="byline-name fn">{{ post.author() }}</span></p>
+ <p class="dateline"><a href="{{ post.permalink() }}" rel="bookmark"><time class="published dt-published" datetime="{{ post.date.isoformat() }}" itemprop="datePublished" title="{{ messages("Publication date") }}">{{ post.formatted_date(date_format) }}</time></a></p>
+ {% if not post.meta('nocomments') and site_has_comments %}
+ <p class="commentline">{{ comments.comment_link(post.permalink(), post._base_path) }}
+ {% endif %}
+ </div>
+ </header>
+ {% if index_teasers %}
+ <div class="p-summary entry-summary">
+ {{ post.text(teaser_only=True) }}
+ {% else %}
+ <div class="e-content entry-content">
+ {{ post.text(teaser_only=False) }}
+ {% endif %}
+ </div>
+ </article>
+{% endfor %}
+</div>
+{{ helper.html_pager() }}
+{{ comments.comment_link_script() }}
+{{ helper.mathjax_script(posts) }}
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/index_helper.tmpl b/nikola/data/themes/base-jinja/templates/index_helper.tmpl
new file mode 100644
index 0000000..2f9e8ea
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/index_helper.tmpl
@@ -0,0 +1,27 @@
+{# -*- coding: utf-8 -*- #}
+{% macro html_pager() %}
+ {% if prevlink or nextlink %}
+ <nav class="postindexpager">
+ <ul class="pager">
+ {% if prevlink %}
+ <li class="previous">
+ <a href="{{ prevlink }}" rel="prev">{{ messages("Newer posts") }}</a>
+ </li>
+ {% endif %}
+ {% if nextlink %}
+ <li class="next">
+ <a href="{{ nextlink }}" rel="next">{{ messages("Older posts") }}</a>
+ </li>
+ {% endif %}
+ </ul>
+ </nav>
+ {% endif %}
+{% endmacro %}
+
+{% macro mathjax_script(posts) %}
+ {% if posts|selectattr("is_mathjax")|list %}
+ <script type="text/x-mathjax-config">
+ MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});</script>
+ <script src="/assets/js/mathjax.js"></script>
+ {% endif %}
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/list.tmpl b/nikola/data/themes/base-jinja/templates/list.tmpl
new file mode 100644
index 0000000..e442864
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/list.tmpl
@@ -0,0 +1,19 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'base.tmpl' %}
+
+{% block content %}
+<article class="listpage">
+ <header>
+ <h1>{{ title }}</h1>
+ </header>
+ {% if items %}
+ <ul class="postlist">
+ {% for text, link in items %}
+ <li><a href="{{ link }}">{{ text }}</a>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p>{{ messages("Nothing found.") }}</p>
+ {% endif %}
+</article>
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/list_post.tmpl b/nikola/data/themes/base-jinja/templates/list_post.tmpl
new file mode 100644
index 0000000..b90f237
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/list_post.tmpl
@@ -0,0 +1,19 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'base.tmpl' %}
+
+{% block content %}
+<article class="listpage">
+ <header>
+ <h1>{{ title }}</h1>
+ </header>
+ {% if posts %}
+ <ul class="postlist">
+ {% for post in posts %}
+ <li><a href="{{ post.permalink() }}" class="listtitle">{{ post.title() }}</a> <time class="listdate" datetime="{{ post.date.isoformat() }}" title="{{ messages("Publication date") }}">{{ post.formatted_date(date_format) }}</time></li>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p>{{ messages("No posts found.") }}</p>
+ {% endif %}
+</article>
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/listing.tmpl b/nikola/data/themes/base-jinja/templates/listing.tmpl
new file mode 100644
index 0000000..ccbc5ba
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/listing.tmpl
@@ -0,0 +1,23 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'base.tmpl' %}
+{% import 'crumbs.tmpl' as ui with context %}
+{% block content %}
+{{ ui.bar(crumbs) }}
+{% if folders or files %}
+<ul>
+{% for name in folders %}
+ <li><a href="{{ name }}"><i class="icon-folder-open"></i> {{ name }}</a>
+{% endfor %}
+{% for name in files %}
+ <li><a href="{{ name }}.html"><i class="icon-file"></i> {{ name }}</a>
+{% endfor %}
+</ul>
+{% endif %}
+{% if code %}
+ {{ code }}
+{% endif %}
+{% if source_link %}
+ <p class="sourceline"><a href="{{ source_link }}" id="sourcelink">{{ messages("Source") }}</a></p>
+{% endif %}
+{% endblock %}
+
diff --git a/nikola/data/themes/base-jinja/templates/post.tmpl b/nikola/data/themes/base-jinja/templates/post.tmpl
new file mode 100644
index 0000000..75c7690
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/post.tmpl
@@ -0,0 +1,39 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'post_helper.tmpl' as helper with context %}
+{% import 'post_header.tmpl' as pheader with context %}
+{% import 'comments_helper.tmpl' as comments with context %}
+{% extends 'base.tmpl' %}
+
+{% block extra_head %}
+ {{ super() }}
+ {% if post.meta('keywords') %}
+ <meta name="keywords" content="{{ post.meta('keywords')|e }}">
+ {% endif %}
+ <meta name="author" content="{{ post.author() }}">
+ {{ helper.open_graph_metadata(post) }}
+ {{ helper.twitter_card_information(post) }}
+ {{ helper.meta_translations(post) }}
+{% endblock %}
+
+{% block content %}
+<article class="post-{{ post.meta('type') }} h-entry hentry postpage" itemscope="itemscope" itemtype="http://schema.org/Article">
+ {{ pheader.html_post_header() }}
+ <div class="e-content entry-content" itemprop="articleBody text">
+ {{ post.text() }}
+ </div>
+ <aside class="postpromonav">
+ <nav>
+ {{ helper.html_tags(post) }}
+ {{ helper.html_pager(post) }}
+ </nav>
+ </aside>
+ {% if not post.meta('nocomments') and site_has_comments %}
+ <section class="comments">
+ <h2>{{ messages("Comments") }}</h2>
+ {{ comments.comment_form(post.permalink(absolute=True), post.title(), post._base_path) }}
+ </section>
+ {% endif %}
+ {{ helper.mathjax_script(post) }}
+</article>
+{{ comments.comment_link_script() }}
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/post_header.tmpl b/nikola/data/themes/base-jinja/templates/post_header.tmpl
new file mode 100644
index 0000000..0ed40b9
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/post_header.tmpl
@@ -0,0 +1,49 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'post_helper.tmpl' as helper with context %}
+{% import 'comments_helper.tmpl' as comments with context %}
+
+{% macro html_title() %}
+{% if title and not post.meta('hidetitle') %}
+ <h1 class="p-name entry-title" itemprop="headline name"><a href="{{ post.permalink() }}" class="u-url">{{ title|e }}</a></h1>
+{% endif %}
+{% endmacro %}
+
+{% macro html_translations(post) %}
+ {% if translations|length > 1 %}
+ <div class="metadata posttranslations translations">
+ <h3 class="posttranslations-intro">{{ messages("Also available in:") }}</h3>
+ {% for langname in translations.keys() %}
+ {% if langname != lang and post.is_translation_available(langname) %}
+ <p><a href="{{ post.permalink(langname) }}" rel="alternate" hreflang="{{ langname }}">{{ messages("LANGUAGE", langname) }}</a></p>
+ {% endif %}
+ {% endfor %}
+ </div>
+ {% endif %}
+{% endmacro %}
+
+{% macro html_sourcelink() %}
+ {% if show_sourcelink %}
+ <p class="sourceline"><a href="{{ post.source_link() }}" id="sourcelink">{{ messages("Source") }}</a></p>
+ {% endif %}
+{% endmacro %}
+
+{% macro html_post_header() %}
+ <header>
+ {{ html_title() }}
+ <div class="metadata">
+ <p class="byline author vcard"><span class="byline-name fn">{{ post.author() }}</span></p>
+ <p class="dateline"><a href="{{ post.permalink() }}" rel="bookmark"><time class="published dt-published" datetime="{{ post.date.isoformat() }}" itemprop="datePublished" title="{{ messages("Publication date") }}">{{ post.formatted_date(date_format) }}</time></a></p>
+ {% if not post.meta('nocomments') and site_has_comments %}
+ <p class="commentline">{{ comments.comment_link(post.permalink(), post._base_path) }}
+ {% endif %}
+ {{ html_sourcelink() }}
+ {% if post.meta('link') %}
+ <p><a href='{{ post.meta('link') }}'>{{ messages("Original site") }}</a></p>
+ {% endif %}
+ {% if post.description() %}
+ <meta name="description" itemprop="description" content="{{ post.description() }}">
+ {% endif %}
+ </div>
+ {{ html_translations(post) }}
+ </header>
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/post_helper.tmpl b/nikola/data/themes/base-jinja/templates/post_helper.tmpl
new file mode 100644
index 0000000..c695e57
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/post_helper.tmpl
@@ -0,0 +1,76 @@
+{# -*- coding: utf-8 -*- #}
+
+{% macro meta_translations(post) %}
+ {% if translations|length > 1 %}
+ {% for langname in translations.keys() %}
+ {% if langname != lang and post.is_translation_available(langname) %}
+ <link rel="alternate" hreflang="{{ langname }}" href="{{ post.permalink(langname) }}">
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+{% endmacro %}
+
+{% macro html_tags(post) %}
+ {% if post.tags %}
+ <ul itemprop="keywords" class="tags">
+ {% for tag in post.tags %}
+ <li><a class="tag p-category" href="{{ _link('tag', tag) }}" rel="tag">{{ tag }}</a></li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+{% endmacro %}
+
+{% macro html_pager(post) %}
+ {% if post.prev_post or post.next_post %}
+ <ul class="pager">
+ {% if post.prev_post %}
+ <li class="previous">
+ <a href="{{ post.prev_post.permalink() }}" rel="prev" title="{{ post.prev_post.title() }}">{{ messages("Previous post") }}</a>
+ </li>
+ {% endif %}
+ {% if post.next_post %}
+ <li class="next">
+ <a href="{{ post.next_post.permalink() }}" rel="next" title="{{ post.next_post.title() }}">{{ messages("Next post") }}</a>
+ </li>
+ {% endif %}
+ </ul>
+ {% endif %}
+{% endmacro %}
+
+{% macro open_graph_metadata(post) %}
+ {% if use_open_graph %}
+ <meta name="og:title" content="{{ post.title()[:70]|e }}">
+ <meta name="og:url" content="{{ abs_link(permalink) }}">
+ {% if post.description() %}
+ <meta name="og:description" content="{{ post.description()[:200]|e }}">
+ {% else %}
+ <meta name="og:description" content="{{ post.text(strip_html=True)[:200]|e }}">
+ {% endif %}
+ <meta name="og:site_name" content="{{ blog_title|e }}">
+ <meta name="og:type" content="article">
+ {% endif %}
+{% endmacro %}
+
+{% macro twitter_card_information(post) %}
+ {% if twitter_card and twitter_card['use_twitter_cards'] %}
+ <meta name="twitter:card" content="{{ twitter_card.get('card', 'summary')|e }}">
+ {% if 'site:id' in twitter_card %}
+ <meta name="twitter:site:id" content="{{ twitter_card['site:id'] }}">
+ {% elif 'site' in twitter_card %}
+ <meta name="twitter:site" content="{{ twitter_card['site'] }}">
+ {% endif %}
+ {% if 'creator:id' in twitter_card %}
+ <meta name="twitter:creator:id" content="{{ twitter_card['creator:id'] }}">
+ {% elif 'creator' in twitter_card %}
+ <meta name="twitter:creator" content="{{ twitter_card['creator'] }}">
+ {% endif %}
+ {% endif %}
+{% endmacro %}
+
+{% macro mathjax_script(post) %}
+ {% if post.is_mathjax %}
+ <script type="text/x-mathjax-config">
+ MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});</script>
+ <script src="/assets/js/mathjax.js"></script>
+ {% endif %}
+{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/post_list_directive.tmpl b/nikola/data/themes/base-jinja/templates/post_list_directive.tmpl
new file mode 100644
index 0000000..ceaec3f
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/post_list_directive.tmpl
@@ -0,0 +1,18 @@
+{# -*- coding: utf-8 -*- #}
+{% block content %}
+<!-- Begin post-list {{ post_list_id }} -->
+<div id="{{ post_list_id }}" class="post-list">
+ {% if posts %}
+ <ul class="post-list">
+ {% for post in posts %}
+ <li class="post-list-item">
+ {{ post.formatted_date(date_format) }}
+ &nbsp;
+ <a href="{{ post.permalink(lang) }}">{{ post.title(lang) }}</a>
+ </li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+</div>
+<!-- End post-list {{ post_list_id }} -->
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/slides.tmpl b/nikola/data/themes/base-jinja/templates/slides.tmpl
new file mode 100644
index 0000000..0ae8fe8
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/slides.tmpl
@@ -0,0 +1,24 @@
+{% block content %}
+<div id="{{ carousel_id }}" class="carousel slide">
+ <ol class="carousel-indicators">
+ {% for i in range(slides_content|length) %}
+ {% if i == 0 %}
+ <li data-target="#{{ carousel_id }}" data-slide-to="{{ i }}" class="active"></li>
+ {% else %}
+ <li data-target="#{{ carousel_id }}" data-slide-to="{{ i }}"></li>
+ {% endif %}
+ {% endfor %}
+ </ol>
+ <div class="carousel-inner">
+ {% for i, image in enumerate(slides_content) %}
+ {% if i == 0 %}
+ <div class="item active"><img src="{{ image }}" alt="" style="margin: 0 auto 0 auto;"></div>
+ {% else %}
+ <div class="item"><img src="{{ image }}" alt="" style="margin: 0 auto 0 auto;"></div>
+ {% endif %}
+ {% endfor %}
+ </div>
+ <a class="left carousel-control" href="#{{ carousel_id }}" data-slide="prev">&lsaquo;</a>
+ <a class="right carousel-control" href="#{{ carousel_id }}" data-slide="next">&rsaquo;</a>
+</div>
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/story.tmpl b/nikola/data/themes/base-jinja/templates/story.tmpl
new file mode 100644
index 0000000..99caaee
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/story.tmpl
@@ -0,0 +1,37 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'post_helper.tmpl' as helper with context %}
+{% import 'post_header.tmpl' as pheader with context %}
+{% import 'comments_helper.tmpl' as comments with context %}
+{% extends 'post.tmpl' %}
+
+{% block extra_head %}
+ {{ super() }}
+ {% if post.meta('keywords') %}
+ <meta name="keywords" content="{{ post.meta('keywords')|e }}">
+ {% endif %}
+ <meta name="author" content="{{ post.author() }}">
+ {{ helper.open_graph_metadata(post) }}
+ {{ helper.twitter_card_information(post) }}
+ {{ helper.meta_translations(post) }}
+ {% if post.description() %}
+ <meta name="description" itemprop="description" content="{{ post.description() }}">
+ {% endif %}
+{% endblock %}
+
+{% block content %}
+<article class="storypage" itemscope="itemscope" itemtype="http://schema.org/Article">
+ <header>
+ {{ pheader.html_title() }}
+ {{ pheader.html_translations(post) }}
+ </header>
+ <div itemprop="articleBody text">
+ {{ post.text() }}
+ </div>
+ {% if site_has_comments and enable_comments and not post.meta('nocomments') %}
+ <section class="comments">
+ <h2>{{ messages("Comments") }}</h2>
+ {{ comments.comment_form(post.permalink(absolute=True), post.title(), post.base_path) }}
+ </section>
+ {% endif %}
+</article>
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/tag.tmpl b/nikola/data/themes/base-jinja/templates/tag.tmpl
new file mode 100644
index 0000000..84f9e68
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/tag.tmpl
@@ -0,0 +1,40 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'list_post.tmpl' %}
+
+{% block extra_head %}
+ {{ super() }}
+ {% if translations|length > 1 and generate_rss %}
+ {% for language in translations %}
+ <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for {{ kind }} {{ tag }} ({{ language }})" href="{{ _link(kind + "_rss", tag, language) }}">
+ {% endfor %}
+ {% elif generate_rss %}
+ <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for {{ kind }} {{ tag }}" href="{{ _link(kind + "_rss", tag) }}">
+ {% endif %}
+{% endblock %}
+
+
+{% block content %}
+<article class="tagpage">
+ <header>
+ <h1>{{ title }}</h1>
+ <div class="metadata">
+ {% if translations|length > 1 and generate_rss %}
+ {% for language in translations %}
+ <p class="feedlink">
+ <a href="{{ _link(kind + "_rss", tag, language) }}" hreflang="{{ language }}" type="application/rss+xml">{{ messages('RSS feed', language) }} ({{ language }})</a>&nbsp;
+ </p>
+ {% endfor %}
+ {% elif generate_rss %}
+ <p class="feedlink"><a href="{{ _link(kind + "_rss", tag) }}" type="application/rss+xml">{{ messages('RSS feed') }}</a></p>
+ {% endif %}
+ </div>
+ </header>
+ {% if posts %}
+ <ul class="postlist">
+ {% for post in posts %}
+ <li><a href="{{ post.permalink() }}" class="listtitle">{{ post.title() }}</a> <time class="listdate" datetime="{{ post.date.isoformat() }}" title="{{ messages("Publication date") }}">{{ post.formatted_date(date_format) }}</time></li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+</article>
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/tagindex.tmpl b/nikola/data/themes/base-jinja/templates/tagindex.tmpl
new file mode 100644
index 0000000..af0a992
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/tagindex.tmpl
@@ -0,0 +1,2 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'index.tmpl' %}
diff --git a/nikola/data/themes/base-jinja/templates/tags.tmpl b/nikola/data/themes/base-jinja/templates/tags.tmpl
new file mode 100644
index 0000000..7bcb7b2
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/tags.tmpl
@@ -0,0 +1,30 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'base.tmpl' %}
+
+{% block content %}
+<article class="tagindex">
+ <header>
+ <h1>{{ title }}</h1>
+ </header>
+ {% if cat_items %}
+ <h2>{{ messages("Categories") }}</h2>
+ <ul class="postlist">
+ {% for text, link in cat_items %}
+ {% if text %}
+ <li><a class="reference" href="{{ link }}">{{ text }}</a></li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ {% if items %}
+ <h2>{{ messages("Tags") }}</h2>
+ {% endif %}
+ {% endif %}
+ {% if items %}
+ <ul class="postlist">
+ {% for text, link in items %}
+ <li><a class="reference listtitle" href="{{ link }}">{{ text }}</a></li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+</article>
+{% endblock %}
diff --git a/nikola/data/themes/base/README.md b/nikola/data/themes/base/README.md
index f92f490..5d1da94 100644
--- a/nikola/data/themes/base/README.md
+++ b/nikola/data/themes/base/README.md
@@ -1,4 +1,4 @@
This theme has almost no styling, it's meant as a basis from which other
-teams can be developed.
+themes can be developed.
Therefore, most "advanced" features, such as slides or galleries, are broken.
diff --git a/nikola/data/themes/base/assets/css/theme.css b/nikola/data/themes/base/assets/css/theme.css
index 2a924f1..6fd1072 100644
--- a/nikola/data/themes/base/assets/css/theme.css
+++ b/nikola/data/themes/base/assets/css/theme.css
@@ -1 +1,255 @@
-/* This file intentionally left blank. */
+@charset "UTF-8";
+
+/*
+ Copyright © 2014 Daniel Aleksandersen and others.
+
+ Permission is hereby granted, free of charge, to any
+ person obtaining a copy of this software and associated
+ documentation files (the "Software"), to deal in the
+ Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the
+ Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice
+ shall be included in all copies or substantial portions of
+ the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+ OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+body {
+ color: #4F5151;
+ font-family: Helvetica, Arial, sans-serif;
+ font-size: 17px;
+ line-height: 1.4;
+ padding: 1em;
+}
+@media print {
+ body {
+ font-family: Garamond, serif;
+ }
+}
+
+#container {
+ margin: 1em auto;
+ max-width: 770px;
+}
+#menu ul,
+#menu ul li,
+.postpromonav .tags,
+.postpromonav .tags li,
+.pager,
+.pager li,
+#toptranslations ul,
+#toptranslations ul li {
+ list-style: none;
+ padding-left: 0;
+ padding-right: 0;
+}
+
+#toptranslations ul {
+ display: inline;
+}
+
+#menu ul li,
+#toptranslations ul li {
+ display: inline-block;
+ margin-right: 1.5em;
+}
+
+#toptranslations h2 {
+ display: inline;
+ font-size: 1em;
+ margin-right: 1.5em;
+}
+
+#menu ul li:dir(rtl),
+#toptranslations ul li:dir(rtl),
+#toptranslations h2:dir(rtl) {
+ margin-left: 1.5em;
+ margin-right: 0;
+}
+
+#toptranslations {
+ text-align: right;
+ float: right;
+}
+
+#toptranslations:dir(rtl) {
+ text-align: left;
+ float: left;
+}
+
+.posttranslations h3 {
+ display: inline;
+ font-size: 1em;
+}
+
+.entry-title {
+ font-size: 2em;
+}
+
+.posttranslations h3:last-child {
+ display: none;
+}
+
+.postindex article {
+ border-bottom: 1px solid #4F5151;
+ padding-bottom: 1em;
+}
+#header {
+ border-bottom: 1px solid #4F5151;
+}
+#footer {
+ border-top: 1px solid #4F5151;
+}
+
+/* Tags */
+.postpromonav {
+ border-bottom: 1px solid #4F5151;
+ border-top: 1px solid #4F5151;
+ margin-top: 1em;
+ padding: .5em 0;
+}
+.postpromonav .tags {
+ text-align: center;
+}
+.metadata p:before,
+.postpromonav .tags li:before,
+.postlist .listdate:before {
+ content: " — ";
+}
+.postlist li {
+ margin-bottom: .33em;
+}
+
+/* Post and archive pagers */
+.postindexpager .pager .next:before {
+ content: "↓ ";
+}
+.postindexpager .pager .previous:before {
+ content: "↑ ";
+}
+.postpromonav .pager .next:after {
+ content: " →";
+}
+.postpromonav .pager .previous:dir(rtl):after {
+ content: " →";
+}
+.postpromonav .pager .previous:before {
+ content: "← ";
+}
+.postpromonav .pager .next:dir(rtl):before {
+ content: "← ";
+}
+
+.metadata p:first-of-type:before,
+.postpromonav .tags li:first-of-type:before {
+ content: "";
+}
+.postpromonav .pager {
+ height: 1em;
+}
+.postpromonav .tags li,
+.postpromonav .pager li {
+ display: inline-block;
+}
+.postpromonav .pager .next {
+ float: right;
+}
+.postpromonav .pager .next:dir(rtl) {
+ float: left;
+}
+.metadata p {
+ display: inline;
+}
+
+#brand {
+ font-size: 3em;
+ line-height: 1;
+}
+
+/* Links */
+:link {
+ color: #1168CC;
+ text-decoration: none;
+}
+:visited {
+ color: #6830BB;
+}
+:link:hover, :visited:hover {
+ color: #0d53a3;
+}
+
+#brand :link,
+#brand :visited {
+ color: inherit;
+}
+
+/* Images */
+img {
+ border: none;
+ line-height: 1;
+}
+
+.postpage img,
+.postpage object,
+.postindex article img,
+.postindex article object {
+ height: auto;
+ max-width: 100%;
+}
+
+/* Comment helpers */
+#disqus_thread {
+ min-height: 325px;
+}
+
+.breadcrumb {
+ padding: 8px 15px;
+ margin-bottom: 20px;
+ list-style: none;
+}
+
+.breadcrumb > li {
+ display: inline-block;
+ margin-right: 0;
+ margin-left: 0;
+}
+
+.breadcrumb > li:after {
+ content: ' / ';
+ color: #888;
+}
+
+.breadcrumb > li:last-of-type:after {
+ content: '';
+ margin-left: 0;
+}
+
+.thumbnails {
+ list-style: none;
+ padding: 0;
+}
+
+.thumbnails > li {
+ display: inline-block;
+ margin-right: 10px;
+}
+
+.thumbnails > li:last-of-type {
+ margin-right: 0;
+}
+
+.codetable .linenos {
+ padding-right: 10px;
+}
diff --git a/nikola/data/themes/base/assets/js/html5.js b/nikola/data/themes/base/assets/js/html5.js
new file mode 100644
index 0000000..448cebd
--- /dev/null
+++ b/nikola/data/themes/base/assets/js/html5.js
@@ -0,0 +1,8 @@
+/*
+ HTML5 Shiv v3.7.0 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
+*/
+(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
+a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/[\w\-]+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}</style>";
+c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
+"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:"3.7.0",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);
+if(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);
diff --git a/nikola/data/themes/base/assets/js/mathjax.js b/nikola/data/themes/base/assets/js/mathjax.js
index 82c1f6c..5e14369 100644
--- a/nikola/data/themes/base/assets/js/mathjax.js
+++ b/nikola/data/themes/base/assets/js/mathjax.js
@@ -5,7 +5,6 @@
window.onload = function () {
setTimeout(function () {
var script = document.createElement("script");
- script.type = "text/javascript";
if (location.protocol == 'https:') {
scriptbase = "https://c328740.ssl.cf1.rackcdn.com/";
} else {
diff --git a/nikola/data/themes/base/bundles b/nikola/data/themes/base/bundles
index 4760181..d87b458 100644
--- a/nikola/data/themes/base/bundles
+++ b/nikola/data/themes/base/bundles
@@ -1,2 +1,2 @@
-assets/css/all.css=rst.css,code.css,theme.css
-assets/css/all-nocdn.css=rst.css,code.css,theme.css
+assets/css/all.css=rst.css,code.css,theme.css,custom.css
+assets/css/all-nocdn.css=rst.css,code.css,theme.css,custom.css
diff --git a/nikola/data/themes/base/messages/messages_bg.py b/nikola/data/themes/base/messages/messages_bg.py
index 6e85212..4158ac8 100644
--- a/nikola/data/themes/base/messages/messages_bg.py
+++ b/nikola/data/themes/base/messages/messages_bg.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Също достъпно в",
+ "%d min remaining to read": "",
"Also available in:": "Също достъпно в:",
"Archive": "Архив",
"Categories": "Категории",
+ "Comments": "",
"LANGUAGE": "Български",
+ "Languages:": "",
"More posts about %s": "Още публикации относно %s",
- "More posts about": "Още публикации относно",
"Newer posts": "Нови публикации",
"Next post": "Следваща публикация",
"No posts found.": "",
"Nothing found.": "",
"Older posts": "Стари публикации",
"Original site": "Оригиналния сайт",
- "Posted": "Публиковано",
"Posted:": "Публиковано:",
"Posts about %s": "Публикации относно %s",
"Posts for year %s": "Публикации за %s година",
"Posts for {month} {year}": "Публикации за {month} {year}",
"Previous post": "Предишна публикация",
+ "Publication date": "",
+ "RSS feed": "",
"Read in English": "Прочетете на български",
"Read more": "Прочети още",
"Source": "Source",
diff --git a/nikola/data/themes/base/messages/messages_ca.py b/nikola/data/themes/base/messages/messages_ca.py
index 220d571..7723f3e 100644
--- a/nikola/data/themes/base/messages/messages_ca.py
+++ b/nikola/data/themes/base/messages/messages_ca.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "També disponibles en",
+ "%d min remaining to read": "",
"Also available in:": "També disponibles en:",
"Archive": "Arxiu",
"Categories": "",
+ "Comments": "",
"LANGUAGE": "Català",
+ "Languages:": "",
"More posts about %s": "Més entrades sobre %s",
- "More posts about": "Més entrades sobre",
"Newer posts": "Entrades posteriors",
"Next post": "Entrada següent",
"No posts found.": "",
"Nothing found.": "",
"Older posts": "Entrades anteriors",
"Original site": "Lloc original",
- "Posted": "Publicat",
"Posted:": "Publicat:",
"Posts about %s": "Entrades sobre %s",
"Posts for year %s": "Entrades de l'any %s",
"Posts for {month} {year}": "",
"Previous post": "Entrada anterior",
+ "Publication date": "",
+ "RSS feed": "",
"Read in English": "Llegeix-ho en català",
"Read more": "Llegeix-ne més",
"Source": "Codi",
diff --git a/nikola/data/themes/base/messages/messages_cs.py b/nikola/data/themes/base/messages/messages_cs.py
index f66c2c4..f80a79f 100644
--- a/nikola/data/themes/base/messages/messages_cs.py
+++ b/nikola/data/themes/base/messages/messages_cs.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Dostupné také v",
+ "%d min remaining to read": "",
"Also available in:": "Dostupné také v",
"Archive": "Archiv",
"Categories": "Kategorie",
+ "Comments": "",
"LANGUAGE": "Čeština",
+ "Languages:": "",
"More posts about %s": "Další příspěvky o %s",
- "More posts about": "Další příspěvky o",
"Newer posts": "Novější příspěvky",
"Next post": "Další příspěvek",
"No posts found.": "",
"Nothing found.": "",
"Older posts": "Starší příspěvky",
"Original site": "Původní stránka",
- "Posted": "Zveřejněno",
"Posted:": "Zveřejněno:",
"Posts about %s": "Příspěvky o %s",
"Posts for year %s": "Příspěvky v roce %s",
"Posts for {month} {year}": "Příspěvky v {month} {year}",
"Previous post": "Předchozí příspěvek",
+ "Publication date": "",
+ "RSS feed": "",
"Read in English": "Číst v češtině",
"Read more": "Číst dál",
"Source": "Zdroj",
diff --git a/nikola/data/themes/base/messages/messages_de.py b/nikola/data/themes/base/messages/messages_de.py
index 41fe015..737e63b 100644
--- a/nikola/data/themes/base/messages/messages_de.py
+++ b/nikola/data/themes/base/messages/messages_de.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Auch verfügbar in",
+ "%d min remaining to read": "",
"Also available in:": "Auch verfügbar in:",
"Archive": "Archiv",
"Categories": "Kategorien",
+ "Comments": "Kommentare",
"LANGUAGE": "Deutsch",
+ "Languages:": "Sprachen:",
"More posts about %s": "Weitere Einträge über %s",
- "More posts about": "Weitere Einträge über",
"Newer posts": "Neuere Einträge",
"Next post": "Nächster Eintrag",
- "No posts found.": "Keine einträge gefunden.",
+ "No posts found.": "Keine Einträge gefunden.",
"Nothing found.": "Nichts gefunden.",
"Older posts": "Ältere Einträge",
"Original site": "Original-Seite",
- "Posted": "Veröffentlicht",
"Posted:": "Veröffentlicht:",
"Posts about %s": "Einträge über %s",
"Posts for year %s": "Einträge aus dem Jahr %s",
"Posts for {month} {year}": "Einträge aus {month} {year}",
"Previous post": "Vorheriger Eintrag",
+ "Publication date": "Veröffentlichungsdatum",
+ "RSS feed": "RSS-Feed",
"Read in English": "Auf Deutsch lesen",
"Read more": "Weiterlesen",
"Source": "Source",
diff --git a/nikola/data/themes/base/messages/messages_el.py b/nikola/data/themes/base/messages/messages_el.py
index f658fa0..aeca302 100644
--- a/nikola/data/themes/base/messages/messages_el.py
+++ b/nikola/data/themes/base/messages/messages_el.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Διαθέσιμο και στα",
+ "%d min remaining to read": "",
"Also available in:": "Διαθέσιμο και στα:",
"Archive": "Αρχείο",
"Categories": "Κατηγορίες",
+ "Comments": "",
"LANGUAGE": "Ελληνικά",
+ "Languages:": "",
"More posts about %s": "Περισσότερες αναρτήσεις για %s",
- "More posts about": "Περισσότερες αναρτήσεις για",
"Newer posts": "Νεότερες αναρτήσεις",
"Next post": "Επόμενη ανάρτηση",
"No posts found.": "",
"Nothing found.": "",
"Older posts": "Παλαιότερες αναρτήσεις",
"Original site": "Ιστοσελίδα αρχικής ανάρτησης",
- "Posted": "Αναρτήθηκε",
"Posted:": "Αναρτήθηκε:",
"Posts about %s": "Αναρτήσεις για %s",
"Posts for year %s": "Αναρτήσεις για το έτος %s",
"Posts for {month} {year}": "Αναρτήσεις για τον {month} του {year}",
"Previous post": "Προηγούμενη ανάρτηση",
+ "Publication date": "",
+ "RSS feed": "",
"Read in English": "Διαβάστε στα Ελληνικά",
"Read more": "Διαβάστε περισσότερα",
"Source": "Πηγαίος κώδικας",
diff --git a/nikola/data/themes/base/messages/messages_en.py b/nikola/data/themes/base/messages/messages_en.py
index e2bff53..bdf2d42 100644
--- a/nikola/data/themes/base/messages/messages_en.py
+++ b/nikola/data/themes/base/messages/messages_en.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Also available in",
+ "%d min remaining to read": "%d min remaining to read",
"Also available in:": "Also available in:",
"Archive": "Archive",
"Categories": "Categories",
+ "Comments": "Comments",
"LANGUAGE": "English",
+ "Languages:": "Languages:",
"More posts about %s": "More posts about %s",
- "More posts about": "More posts about",
"Newer posts": "Newer posts",
"Next post": "Next post",
"No posts found.": "No posts found.",
"Nothing found.": "Nothing found.",
"Older posts": "Older posts",
"Original site": "Original site",
- "Posted": "Posted",
"Posted:": "Posted:",
"Posts about %s": "Posts about %s",
"Posts for year %s": "Posts for year %s",
"Posts for {month} {year}": "Posts for {month} {year}",
"Previous post": "Previous post",
+ "Publication date": "Publication date",
+ "RSS feed": "RSS feed",
"Read in English": "Read in English",
"Read more": "Read more",
"Source": "Source",
diff --git a/nikola/data/themes/base/messages/messages_eo.py b/nikola/data/themes/base/messages/messages_eo.py
index f59a441..e439e6b 100644
--- a/nikola/data/themes/base/messages/messages_eo.py
+++ b/nikola/data/themes/base/messages/messages_eo.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Ankaŭ disponebla en",
+ "%d min remaining to read": "",
"Also available in:": "Ankaŭ disponebla en:",
"Archive": "Arĥivo",
"Categories": "Kategorioj",
+ "Comments": "",
"LANGUAGE": "Anglalingve",
+ "Languages:": "",
"More posts about %s": "Pli artikoloj pri %s",
- "More posts about": "Pli artikoloj pri",
"Newer posts": "Pli novaj artikoloj",
"Next post": "Venonta artikolo",
"No posts found.": "",
"Nothing found.": "",
"Older posts": "Pli malnovaj artikoloj",
"Original site": "Originala interretejo",
- "Posted": "Skribita",
"Posted:": "Skribita:",
"Posts about %s": "Artikoloj pri %s",
"Posts for year %s": "Artikoloj de la jaro %s",
"Posts for {month} {year}": "Artikoloj skribitaj en {month} {year}",
"Previous post": "Antaŭa artikolo",
+ "Publication date": "",
+ "RSS feed": "",
"Read in English": "Legu ĝin en Esperanto",
"Read more": "Legu plu",
"Source": "Fonto",
diff --git a/nikola/data/themes/base/messages/messages_es.py b/nikola/data/themes/base/messages/messages_es.py
index 1923683..0905f00 100644
--- a/nikola/data/themes/base/messages/messages_es.py
+++ b/nikola/data/themes/base/messages/messages_es.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "También disponible en",
+ "%d min remaining to read": "restan %d minutos",
"Also available in:": "También disponible en:",
"Archive": "Archivo",
"Categories": "Categorías",
+ "Comments": "Comentarios",
"LANGUAGE": "Español",
+ "Languages:": "Idiomas:",
"More posts about %s": "Más posts sobre %s",
- "More posts about": "Más posts sobre",
"Newer posts": "Posts posteriores",
"Next post": "Siguiente post",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "No se encontraron posts",
+ "Nothing found.": "No encontrado",
"Older posts": "Posts anteriores",
"Original site": "Sitio original",
- "Posted": "Publicado",
"Posted:": "Publicado:",
"Posts about %s": "Posts sobre %s",
"Posts for year %s": "Posts del año %s",
"Posts for {month} {year}": "Posts de {month} {year}",
"Previous post": "Post anterior",
+ "Publication date": "Fecha de publicación",
+ "RSS feed": "feed RSS",
"Read in English": "Leer en español",
"Read more": "Leer más",
"Source": "Código",
diff --git a/nikola/data/themes/base/messages/messages_et.py b/nikola/data/themes/base/messages/messages_et.py
index 058ab5f..f473985 100644
--- a/nikola/data/themes/base/messages/messages_et.py
+++ b/nikola/data/themes/base/messages/messages_et.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Saadaval ka",
+ "%d min remaining to read": "",
"Also available in:": "Saadaval ka:",
"Archive": "Arhiiv",
"Categories": "Kategooriad",
+ "Comments": "",
"LANGUAGE": "Eesti",
+ "Languages:": "",
"More posts about %s": "Veel postitusi %s kohta",
- "More posts about": "Veel postitusi kohta",
"Newer posts": "Uued postitused",
"Next post": "Järgmine postitus",
"No posts found.": "",
"Nothing found.": "",
"Older posts": "Vanemad postitused",
"Original site": "Algallikas",
- "Posted": "Postitatud",
"Posted:": "Postitatud:",
"Posts about %s": "Postitused %s kohta",
"Posts for year %s": "Postitused aastast %s",
"Posts for {month} {year}": "Postitused {year} aasta kuust {month} ",
"Previous post": "Eelmine postitus",
+ "Publication date": "",
+ "RSS feed": "",
"Read in English": "Loe eesti keeles",
"Read more": "Loe veel",
"Source": "Lähtekood",
diff --git a/nikola/data/themes/base/messages/messages_eu.py b/nikola/data/themes/base/messages/messages_eu.py
index a8eb743..8958d42 100644
--- a/nikola/data/themes/base/messages/messages_eu.py
+++ b/nikola/data/themes/base/messages/messages_eu.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Eskuragarria hemen ere",
+ "%d min remaining to read": "",
"Also available in:": "Eskuragarria hemen ere:",
"Archive": "Artxiboa",
"Categories": "Kategoriak",
+ "Comments": "",
"LANGUAGE": "Euskara",
+ "Languages:": "",
"More posts about %s": "%s-ri buruzko post gehiago",
- "More posts about": "-ri buruzko post gehiago",
"Newer posts": "Post berrienak",
"Next post": "Hurrengo posta",
"No posts found.": "",
"Nothing found.": "",
"Older posts": "Post zaharrenak",
"Original site": "Jatorrizko orria",
- "Posted": "Argitaratuta",
"Posted:": "Argitaratuta:",
"Posts about %s": "%s-ri buruzko postak",
"Posts for year %s": "%s. urteko postak",
"Posts for {month} {year}": "{year}ko {month}ren postak",
"Previous post": "Aurreko posta",
+ "Publication date": "",
+ "RSS feed": "",
"Read in English": "Euskaraz irakurri",
"Read more": "Irakurri gehiago",
"Source": "Iturria",
diff --git a/nikola/data/themes/base/messages/messages_fa.py b/nikola/data/themes/base/messages/messages_fa.py
index 4475e1b..49cfda5 100644
--- a/nikola/data/themes/base/messages/messages_fa.py
+++ b/nikola/data/themes/base/messages/messages_fa.py
@@ -2,30 +2,32 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "همچنین قابل دسترس از",
+ "%d min remaining to read": "",
"Also available in:": "همچنین قابل دسترس از:",
"Archive": "آرشیو",
"Categories": "دسته‌ها",
+ "Comments": "دیدگاه‌‌‌ها",
"LANGUAGE": "فارسی",
+ "Languages:": "زبان‌‌ها:",
"More posts about %s": "ارسال‌های بیشتر دربارهٔ%s",
- "More posts about": "ارسال‌های بیشتر دربارهٔ",
"Newer posts": "ارسال‌های جدید‌تر",
"Next post": "ارسال بعدی",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "هیچ پستی پیدا نشد.",
+ "Nothing found.": "هیچ‌چیزی پیدا نشد.",
"Older posts": "پست‌های قدیمی‌تر",
"Original site": "سایت اصلی",
- "Posted": "ارسال شده",
"Posted:": "ارسال شده:",
"Posts about %s": "ارسال‌ها دربارهٔ %s",
"Posts for year %s": "ارسال‌ها برای سال %s",
"Posts for {month} {year}": "ارسال برای {month} {year}",
"Previous post": "ارسال پیشین",
+ "Publication date": "تاریخ انتشار",
+ "RSS feed": "خوراک",
"Read in English": "به فارسی بخوانید",
"Read more": "بیشتر بخوانید",
"Source": "منبع",
"Tags and Categories": "برچسب‌ها و دسته‌ها",
"Tags": "برچسب‌ها",
"old posts, page %d": "صفحهٔ ارسال‌های قدیمی %d",
- "page %d": "",
+ "page %d": "برگه %d",
}
diff --git a/nikola/data/themes/base/messages/messages_fi.py b/nikola/data/themes/base/messages/messages_fi.py
index 42e6fa2..b621459 100644
--- a/nikola/data/themes/base/messages/messages_fi.py
+++ b/nikola/data/themes/base/messages/messages_fi.py
@@ -2,30 +2,32 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Saatavilla myös",
+ "%d min remaining to read": "",
"Also available in:": "Saatavilla myös:",
"Archive": "Arkisto",
"Categories": "Kategoriat",
+ "Comments": "Kommentit",
"LANGUAGE": "Suomi",
+ "Languages:": "Kielet:",
"More posts about %s": "Lisää postauksia aiheesta %s",
- "More posts about": "Lisää postauksia aiheesta",
"Newer posts": "Uudempia postauksia",
"Next post": "Seuraava postaus",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "Postauksia ei löytynyt.",
+ "Nothing found.": "Ei hakutuloksia.",
"Older posts": "Vanhempia postauksia",
"Original site": "Alkuperäinen sivusto",
- "Posted": "Postattu",
"Posted:": "Postattu:",
"Posts about %s": "Postauksia aiheesta %s",
"Posts for year %s": "Postauksia vuodelta %s",
"Posts for {month} {year}": "Postauksia ajalle {month} {year}",
"Previous post": "Vanhempia postauksia",
+ "Publication date": "Julkaisupäivämäärä",
+ "RSS feed": "RSS syöte",
"Read in English": "Lue suomeksi",
"Read more": "Lue lisää",
"Source": "Lähde",
"Tags and Categories": "Tagit ja kategoriat",
"Tags": "Tagit",
- "old posts, page %d": "vanhojen postauksien, sivu %d",
+ "old posts, page %d": "vanhoja postauksia, sivu %d",
"page %d": "sivu %d",
}
diff --git a/nikola/data/themes/base/messages/messages_fr.py b/nikola/data/themes/base/messages/messages_fr.py
index 484d695..316ba20 100644
--- a/nikola/data/themes/base/messages/messages_fr.py
+++ b/nikola/data/themes/base/messages/messages_fr.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Egalement disponible en",
+ "%d min remaining to read": "",
"Also available in:": "Egalement disponible en:",
"Archive": "Archives",
"Categories": "Catégories",
+ "Comments": "Commentaires",
"LANGUAGE": "Français",
+ "Languages:": "Langues:",
"More posts about %s": "Plus d'articles sur %s",
- "More posts about": "Plus d'articles sur",
"Newer posts": "Billets récents",
"Next post": "Article suivant",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "Pas de billets.",
+ "Nothing found.": "Pas de résultats.",
"Older posts": "Anciens articles",
"Original site": "Site d'origine",
- "Posted": "Publié",
"Posted:": "Publié:",
"Posts about %s": "Articles sur %s",
"Posts for year %s": "Articles de l'année %s",
"Posts for {month} {year}": "Articles de {month} {year}",
"Previous post": "Article précédent",
+ "Publication date": "Date de publication",
+ "RSS feed": "Flux RSS",
"Read in English": "Lire en français",
"Read more": "Lire la suite",
"Source": "Source",
diff --git a/nikola/data/themes/base/messages/messages_hi.py b/nikola/data/themes/base/messages/messages_hi.py
index f72d5af..6b53e01 100644
--- a/nikola/data/themes/base/messages/messages_hi.py
+++ b/nikola/data/themes/base/messages/messages_hi.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "उपलब्ध भाषाएँ",
+ "%d min remaining to read": "",
"Also available in:": "उपलब्ध भाषाएँ:",
"Archive": "आर्काइव",
"Categories": "श्रेणियाँ",
+ "Comments": "",
"LANGUAGE": "हिन्दी",
+ "Languages:": "",
"More posts about %s": "%s के बारे में अौर पोस्टें",
- "More posts about": " के बारे में अौर पोस्टें",
"Newer posts": "नई पोस्टें",
"Next post": "अगली पोस्ट",
"No posts found.": "",
"Nothing found.": "",
"Older posts": "पुरानी पोस्टें",
"Original site": "असली साइट",
- "Posted": "पोस्टेड",
"Posted:": "पोस्टेड:",
"Posts about %s": "%s के बारे में पोस्टें",
"Posts for year %s": "साल %s की पोस्टें",
"Posts for {month} {year}": "{month} {year} की पोस्टें",
"Previous post": "पिछली पोस्ट",
+ "Publication date": "",
+ "RSS feed": "",
"Read in English": "हिन्दी में पढ़िए",
"Read more": "और पढ़िए",
"Source": "सोर्स",
diff --git a/nikola/data/themes/base/messages/messages_hr.py b/nikola/data/themes/base/messages/messages_hr.py
index ee5ce41..c3343c9 100644
--- a/nikola/data/themes/base/messages/messages_hr.py
+++ b/nikola/data/themes/base/messages/messages_hr.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Također dostupno i u",
+ "%d min remaining to read": "",
"Also available in:": "Također dostupno i u:",
"Archive": "Arhiva",
"Categories": "Kategorije",
+ "Comments": "Komentari",
"LANGUAGE": "hrvatski",
+ "Languages:": "Jezici:",
"More posts about %s": "Više postova o %s",
- "More posts about": "Više postova o",
"Newer posts": "Noviji postovi",
"Next post": "Sljedeći post",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "Nema postova.",
+ "Nothing found.": "Nema ničeg.",
"Older posts": "Stariji postovi",
"Original site": "Izvorna stranica",
- "Posted": "Objavljeno",
"Posted:": "Objavljeno:",
"Posts about %s": "Postovi o %s",
"Posts for year %s": "Postovi za godinu %s",
"Posts for {month} {year}": "Postovi za {month} {year}",
"Previous post": "Prethodni post",
+ "Publication date": "Nadnevak objave",
+ "RSS feed": "RSS kanal",
"Read in English": "Čitaj na hrvatskom",
"Read more": "Čitaj dalje",
"Source": "Izvor",
diff --git a/nikola/data/themes/base/messages/messages_it.py b/nikola/data/themes/base/messages/messages_it.py
index 87e25e5..b248d34 100644
--- a/nikola/data/themes/base/messages/messages_it.py
+++ b/nikola/data/themes/base/messages/messages_it.py
@@ -2,27 +2,29 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Anche disponibile in",
+ "%d min remaining to read": "ancora %d minuti",
"Also available in:": "Anche disponibile in:",
"Archive": "Archivio",
"Categories": "Categorie",
+ "Comments": "Commenti",
"LANGUAGE": "Italiano",
+ "Languages:": "Lingue:",
"More posts about %s": "Altri articoli collegati %s",
- "More posts about": "Altri articoli collegati",
"Newer posts": "Articoli recenti",
"Next post": "Articolo successivo",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "Nessun articolo trovato.",
+ "Nothing found.": "Non trovato.",
"Older posts": "Articoli precedenti",
"Original site": "Sito originale",
- "Posted": "Pubblicato",
"Posted:": "Pubblicato:",
"Posts about %s": "Articoli su %s",
"Posts for year %s": "Articoli per l'anno %s",
"Posts for {month} {year}": "Articoli per {month} {year}",
"Previous post": "Articolo precedente",
+ "Publication date": "Data di pubblicazione",
+ "RSS feed": "Flusso RSS",
"Read in English": "Leggi in italiano",
- "Read more": "Espandi",
+ "Read more": "Continua la lettura",
"Source": "Sorgente",
"Tags and Categories": "Tags e Categorie",
"Tags": "Tags",
diff --git a/nikola/data/themes/base/messages/messages_ja.py b/nikola/data/themes/base/messages/messages_ja.py
index 2df16a4..4b0fd54 100644
--- a/nikola/data/themes/base/messages/messages_ja.py
+++ b/nikola/data/themes/base/messages/messages_ja.py
@@ -2,30 +2,32 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "他の言語で読む",
+ "%d min remaining to read": "",
"Also available in:": "他の言語で読む:",
"Archive": "過去の記事",
"Categories": "カテゴリー",
+ "Comments": "コメント",
"LANGUAGE": "日本語",
+ "Languages:": "言語 :",
"More posts about %s": "タグ: %s",
- "More posts about": "タグ:",
"Newer posts": "新しい記事",
"Next post": "次の記事",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "記事はありません",
+ "Nothing found.": "なにも見つかりませんでした",
"Older posts": "過去の記事",
"Original site": "元のサイト",
- "Posted": "投稿日時",
"Posted:": "投稿日時:",
"Posts about %s": "%sについての記事",
"Posts for year %s": "%s年の記事",
"Posts for {month} {year}": "{year}年{month}月の記事",
"Previous post": "前の記事",
+ "Publication date": "投稿日",
+ "RSS feed": "RSS フィード",
"Read in English": "日本語で読む",
"Read more": "続きを読む",
"Source": "ソース",
"Tags and Categories": "タグとカテゴリー",
"Tags": "タグ",
"old posts, page %d": "前の記事 %dページ目",
- "page %d": "",
+ "page %d": "ページ %d",
}
diff --git a/nikola/data/themes/base/messages/messages_nb.py b/nikola/data/themes/base/messages/messages_nb.py
index 44fde8a..f6232df 100644
--- a/nikola/data/themes/base/messages/messages_nb.py
+++ b/nikola/data/themes/base/messages/messages_nb.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Også tilgjengelig på",
+ "%d min remaining to read": "",
"Also available in:": "Også tilgjengelig på:",
"Archive": "Arkiv",
"Categories": "Kategorier",
+ "Comments": "",
"LANGUAGE": "norsk",
+ "Languages:": "",
"More posts about %s": "Flere innlegg om %s",
- "More posts about": "Flere innlegg om",
"Newer posts": "Nyere innlegg",
"Next post": "Neste innlegg",
"No posts found.": "",
"Nothing found.": "",
"Older posts": "Eldre innlegg",
"Original site": "Opprinnelig side",
- "Posted": "Publisert",
"Posted:": "Publisert:",
"Posts about %s": "Innlegg om %s",
"Posts for year %s": "Innlegg fra %s",
"Posts for {month} {year}": "Innlegg fra {month} {year}",
"Previous post": "Forrige innlegg",
+ "Publication date": "",
+ "RSS feed": "",
"Read in English": "Les på norsk",
"Read more": "Les mer",
"Source": "Kilde",
diff --git a/nikola/data/themes/base/messages/messages_nl.py b/nikola/data/themes/base/messages/messages_nl.py
index 1952d2e..7cba96b 100644
--- a/nikola/data/themes/base/messages/messages_nl.py
+++ b/nikola/data/themes/base/messages/messages_nl.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Ook beschikbaar in",
+ "%d min remaining to read": "%d min resterende leestijd ",
"Also available in:": "Ook beschikbaar in:",
"Archive": "Archief",
"Categories": "Categorieën",
+ "Comments": "Commentaar",
"LANGUAGE": "Nederlands",
+ "Languages:": "Talen:",
"More posts about %s": "Meer berichten over %s",
- "More posts about": "Meer berichten over",
"Newer posts": "Nieuwere berichten",
"Next post": "Volgend bericht",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "Geen berichten gevonden.",
+ "Nothing found.": "Niets gevonden.",
"Older posts": "Oudere berichten",
"Original site": "Originele site",
- "Posted": "Geplaatst",
"Posted:": "Geplaatst:",
"Posts about %s": "Berichten over %s",
"Posts for year %s": "Berichten voor het jaar %s",
"Posts for {month} {year}": "Berichten voor {month} {year}",
"Previous post": "Vorig bericht",
+ "Publication date": "Publicatiedatum",
+ "RSS feed": "RSS-feed",
"Read in English": "Lees in het Nederlands",
"Read more": "Lees verder",
"Source": "Bron",
diff --git a/nikola/data/themes/base/messages/messages_pl.py b/nikola/data/themes/base/messages/messages_pl.py
index a1183ba..6b6e48d 100644
--- a/nikola/data/themes/base/messages/messages_pl.py
+++ b/nikola/data/themes/base/messages/messages_pl.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Również dostępny w językach",
+ "%d min remaining to read": "zostało %d minut czytania",
"Also available in:": "Również dostępny w językach:",
"Archive": "Archiwum",
"Categories": "Kategorie",
+ "Comments": "Komentarze",
"LANGUAGE": "polski",
+ "Languages:": "Języki:",
"More posts about %s": "Więcej postów o %s",
- "More posts about": "Więcej postów o",
"Newer posts": "Nowsze posty",
"Next post": "Następny post",
"No posts found.": "Nie znaleziono żadnych postów.",
"Nothing found.": "Nic nie znaleziono.",
"Older posts": "Starsze posty",
"Original site": "Oryginalna strona",
- "Posted": "Opublikowano",
"Posted:": "Opublikowano:",
"Posts about %s": "Posty o %s",
"Posts for year %s": "Posty z roku %s",
"Posts for {month} {year}": "Posty z {month} {year}",
"Previous post": "Poprzedni post",
+ "Publication date": "Data publikacji",
+ "RSS feed": "Kanał RSS",
"Read in English": "Czytaj po polsku",
"Read more": "Czytaj więcej",
"Source": "Źródło",
diff --git a/nikola/data/themes/base/messages/messages_pt_br.py b/nikola/data/themes/base/messages/messages_pt_br.py
index bf515e4..c86b2f8 100644
--- a/nikola/data/themes/base/messages/messages_pt_br.py
+++ b/nikola/data/themes/base/messages/messages_pt_br.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Também disponível em",
+ "%d min remaining to read": "%d mín restante para leitura",
"Also available in:": "Também disponível em:",
"Archive": "Arquivo",
"Categories": "Categorias",
+ "Comments": "Comentários",
"LANGUAGE": "Português",
+ "Languages:": "Idiomas:",
"More posts about %s": "Mais posts sobre %s",
- "More posts about": "Mais posts sobre",
"Newer posts": "Posts mais recentes",
"Next post": "Próximo post",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "Nenhum tópico encontrado.",
+ "Nothing found.": "Nada encontrado.",
"Older posts": "Posts mais antigos",
"Original site": "Site original",
- "Posted": "Publicado",
"Posted:": "Publicado:",
"Posts about %s": "Posts sobre %s",
"Posts for year %s": "Posts do ano %s",
"Posts for {month} {year}": "Posts de {month} {year}",
"Previous post": "Post anterior",
+ "Publication date": "Data de publicação",
+ "RSS feed": "Feed RSS",
"Read in English": "Ler em português",
"Read more": "Leia mais",
"Source": "Código",
diff --git a/nikola/data/themes/base/messages/messages_ru.py b/nikola/data/themes/base/messages/messages_ru.py
index fb33b85..7c038cc 100644
--- a/nikola/data/themes/base/messages/messages_ru.py
+++ b/nikola/data/themes/base/messages/messages_ru.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Также доступно на",
+ "%d min remaining to read": "%d минут чтения осталось",
"Also available in:": "Также доступно на:",
"Archive": "Архив",
"Categories": "Категории",
+ "Comments": "Комментарии",
"LANGUAGE": "Русский",
+ "Languages:": "Языки:",
"More posts about %s": "Больше записей о %s",
- "More posts about": "Больше записей о",
"Newer posts": "Новые записи",
"Next post": "Следующая запись",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "Записей не найдено.",
+ "Nothing found.": "Ничего не найдено.",
"Older posts": "Старые записи",
"Original site": "Оригинальный сайт",
- "Posted": "Опубликовано",
"Posted:": "Опубликовано:",
"Posts about %s": "Записи о %s",
"Posts for year %s": "Записи за %s год",
"Posts for {month} {year}": "Записи за {month} {year}",
"Previous post": "Предыдущая запись",
+ "Publication date": "Дата опубликования",
+ "RSS feed": "RSS лента",
"Read in English": "Прочесть по-русски",
"Read more": "Читать далее",
"Source": "Источник",
diff --git a/nikola/data/themes/base/messages/messages_sk.py b/nikola/data/themes/base/messages/messages_sk.py
new file mode 100644
index 0000000..3b56a58
--- /dev/null
+++ b/nikola/data/themes/base/messages/messages_sk.py
@@ -0,0 +1,33 @@
+# -*- encoding:utf-8 -*-
+from __future__ import unicode_literals
+
+MESSAGES = {
+ "%d min remaining to read": "",
+ "Also available in:": "Tiež dostupné v:",
+ "Archive": "Archív",
+ "Categories": "Kategórie",
+ "Comments": "Komentáre",
+ "LANGUAGE": "Slovenčina",
+ "Languages:": "Jazyky:",
+ "More posts about %s": "Viac príspevkov o %s",
+ "Newer posts": "Novšie príspevky",
+ "Next post": "Nasledujúci príspevok",
+ "No posts found.": "Žiadne príspevky nenájdené",
+ "Nothing found.": "Nič nenájdené.",
+ "Older posts": "Staršie príspevky",
+ "Original site": "Pôvodná stránka",
+ "Posted:": "Zverejnené:",
+ "Posts about %s": "Príspevky o %s",
+ "Posts for year %s": "Príspevky z roku %s",
+ "Posts for {month} {year}": "Príspevky za mesiac {month} z roku {year}",
+ "Previous post": "Predchádzajúci príspevok",
+ "Publication date": "Dátum zverejnenia",
+ "RSS feed": "RSS kanál",
+ "Read in English": "Čítať v slovenčine",
+ "Read more": "Čítať ďalej",
+ "Source": "Zdroj",
+ "Tags and Categories": "Štítky a kategórie",
+ "Tags": "Štítky",
+ "old posts, page %d": "staré príspevky, strana %d",
+ "page %d": "stránka %d",
+}
diff --git a/nikola/data/themes/base/messages/messages_sl.py b/nikola/data/themes/base/messages/messages_sl.py
index 92ad483..53045e3 100644
--- a/nikola/data/themes/base/messages/messages_sl.py
+++ b/nikola/data/themes/base/messages/messages_sl.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "Na voljo tudi v",
+ "%d min remaining to read": "za prebrati preostalo še %d min",
"Also available in:": "Na voljo tudi v:",
"Archive": "Arhiv",
"Categories": "Kategorije",
+ "Comments": "Komentarji",
"LANGUAGE": "Slovenščina",
+ "Languages:": "Jeziki:",
"More posts about %s": "Več objav o %s",
- "More posts about": "Več objav o",
"Newer posts": "Novejše objave",
"Next post": "Naslednja objava",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "Ni najdenih objav.",
+ "Nothing found.": "Brez zadetkov.",
"Older posts": "Starejše objave",
"Original site": "Izvorna spletna stran",
- "Posted": "Objavljeno",
"Posted:": "Objavljeno:",
"Posts about %s": "Objave o %s",
"Posts for year %s": "Objave za leto %s",
"Posts for {month} {year}": "Objave za {month} {year}",
"Previous post": "Prejšnja objava",
+ "Publication date": "Datum objave",
+ "RSS feed": "vir RSS",
"Read in English": "Beri v slovenščini",
"Read more": "Več o tem",
"Source": "Izvor",
diff --git a/nikola/data/themes/base/messages/messages_sl_si.py b/nikola/data/themes/base/messages/messages_sl_si.py
deleted file mode 120000
index 152e151..0000000
--- a/nikola/data/themes/base/messages/messages_sl_si.py
+++ /dev/null
@@ -1 +0,0 @@
-messages_sl.py \ No newline at end of file
diff --git a/nikola/data/themes/base/messages/messages_tr.py b/nikola/data/themes/base/messages/messages_tr.py
index ad92768..df9c4eb 120000..100644
--- a/nikola/data/themes/base/messages/messages_tr.py
+++ b/nikola/data/themes/base/messages/messages_tr.py
@@ -1 +1,33 @@
-messages_tr_tr.py \ No newline at end of file
+# -*- encoding:utf-8 -*-
+from __future__ import unicode_literals
+
+MESSAGES = {
+ "%d min remaining to read": "",
+ "Also available in:": "Şu dilde de mevcut:",
+ "Archive": "Arşiv",
+ "Categories": "Kategoriler",
+ "Comments": "Yorumlar",
+ "LANGUAGE": "Türkçe",
+ "Languages:": "Diller:",
+ "More posts about %s": "%s ilgili diğer yazılar",
+ "Newer posts": "Daha yeni yazılar",
+ "Next post": "Sonraki yazı",
+ "No posts found.": "Yazı bulunamadı.",
+ "Nothing found.": "Hiçbir şey bulunamadı.",
+ "Older posts": "Daha eski yazılar",
+ "Original site": "Orjinal web sayfası",
+ "Posted:": "Yayın tarihi:",
+ "Posts about %s": "%s ile ilgili yazılar",
+ "Posts for year %s": "%s yılındaki yazılar",
+ "Posts for {month} {year}": "{month} {year} göre yazılar",
+ "Previous post": "Önceki yazı",
+ "Publication date": "Yayınlanma tarihi",
+ "RSS feed": "RSS kaynağı",
+ "Read in English": "Türkçe olarak oku",
+ "Read more": "Devamını oku",
+ "Source": "Kaynak",
+ "Tags and Categories": "Etiketler ve Kategoriler",
+ "Tags": "Etiketler",
+ "old posts, page %d": "eski yazılar, sayfa %d",
+ "page %d": "sayfa %d",
+}
diff --git a/nikola/data/themes/base/messages/messages_tr_tr.py b/nikola/data/themes/base/messages/messages_tr_tr.py
deleted file mode 100644
index 95c5736..0000000
--- a/nikola/data/themes/base/messages/messages_tr_tr.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# -*- encoding:utf-8 -*-
-from __future__ import unicode_literals
-
-MESSAGES = {
- "Also available in": "Şu dilde de mevcut",
- "Also available in:": "Şu dilde de mevcut:",
- "Archive": "Arşiv",
- "Categories": "Kategoriler",
- "LANGUAGE": "Türkçe",
- "More posts about %s": "%s ilgili diğer yazılar",
- "More posts about": " ilgili diğer yazılar",
- "Newer posts": "Daha yeni yazılar",
- "Next post": "Sonraki yazı",
- "No posts found.": "",
- "Nothing found.": "",
- "Older posts": "Daha eski yazılar",
- "Original site": "Orjinal web sayfası",
- "Posted": "Yayın tarihi",
- "Posted:": "Yayın tarihi:",
- "Posts about %s": "%s ile ilgili yazılar",
- "Posts for year %s": "%s yılındaki yazılar",
- "Posts for {month} {year}": "{month} {year} göre yazılar",
- "Previous post": "Önceki yazı",
- "Read in English": "Türkçe olarak oku",
- "Read more": "Devamını oku",
- "Source": "Kaynak",
- "Tags and Categories": "Etiketler ve Kategoriler",
- "Tags": "Etiketler",
- "old posts, page %d": "eski yazılar, sayfa %d",
- "page %d": "sayfa %d",
-}
diff --git a/nikola/data/themes/base/messages/messages_ur.py b/nikola/data/themes/base/messages/messages_ur.py
index 794861d..204d95f 100644
--- a/nikola/data/themes/base/messages/messages_ur.py
+++ b/nikola/data/themes/base/messages/messages_ur.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "ان زبانوں میں بھی دستیاب",
+ "%d min remaining to read": "%d منٹ کا مطالعہ باقی",
"Also available in:": "ان زبانوں میں بھی دستیاب:",
"Archive": "آرکائیو",
"Categories": "زمرے",
+ "Comments": "تبصرے",
"LANGUAGE": "اردو",
+ "Languages:": "زبانیں:",
"More posts about %s": "%s کے بارے میں مزید تحاریر",
- "More posts about": " کے بارے میں مزید تحاریر",
"Newer posts": "نئی تحاریر",
"Next post": "اگلی تحریر",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "کوئی تحریر نہیں مل سکی۔",
+ "Nothing found.": "کچھ نہیں مل سکا۔",
"Older posts": "پرانی تحاریر",
"Original site": "اصلی سائٹ",
- "Posted": "اشاعت",
"Posted:": "اشاعت:",
"Posts about %s": "%s کے بارے میں تحاریر",
"Posts for year %s": "سال %s کی تحاریر",
"Posts for {month} {year}": "{month} {year} کی تحاریر",
"Previous post": "پچھلی تحریر",
+ "Publication date": "تاریخِ اشاعت",
+ "RSS feed": "آر ایس ایس فیڈ",
"Read in English": "اردو میں پڑھیے",
"Read more": "مزید پڑھیے",
"Source": "سورس",
diff --git a/nikola/data/themes/base/messages/messages_zh_cn.py b/nikola/data/themes/base/messages/messages_zh_cn.py
index 2f937c7..525cb45 100644
--- a/nikola/data/themes/base/messages/messages_zh_cn.py
+++ b/nikola/data/themes/base/messages/messages_zh_cn.py
@@ -2,25 +2,27 @@
from __future__ import unicode_literals
MESSAGES = {
- "Also available in": "其他语言版本",
+ "%d min remaining to read": "",
"Also available in:": "其他语言版本:",
"Archive": "文章存档",
"Categories": "分类",
+ "Comments": "",
"LANGUAGE": "简体中文",
+ "Languages:": "",
"More posts about %s": "更多相关文章: %s",
- "More posts about": "更多相关文章:",
"Newer posts": "新一篇",
"Next post": "后一篇",
"No posts found.": "",
"Nothing found.": "",
"Older posts": "旧一篇",
"Original site": "原文地址",
- "Posted": "发表于",
"Posted:": "发表于:",
"Posts about %s": "文章分类:%s",
"Posts for year %s": "%s年文章",
"Posts for {month} {year}": "{year}年{month}月文章",
"Previous post": "前一篇",
+ "Publication date": "",
+ "RSS feed": "",
"Read in English": "中文版",
"Read more": "更多",
"Source": "源代码",
diff --git a/nikola/data/themes/base/templates/base.tmpl b/nikola/data/themes/base/templates/base.tmpl
index 8a90349..f587593 100644
--- a/nikola/data/themes/base/templates/base.tmpl
+++ b/nikola/data/themes/base/templates/base.tmpl
@@ -1,45 +1,25 @@
## -*- coding: utf-8 -*-
<%namespace name="base" file="base_helper.tmpl" import="*"/>
+<%namespace name="header" file="base_header.tmpl" import="*"/>
+<%namespace name="footer" file="base_footer.tmpl" import="*"/>
<%namespace name="annotations" file="annotation_helper.tmpl"/>
${set_locale(lang)}
-<!DOCTYPE html>
-<html
-%if comment_system == 'facebook':
-xmlns:fb="http://ogp.me/ns/fb#"
-%endif
-lang="${lang}">
-<head>
- ${base.html_head()}
- <%block name="extra_head">
- </%block>
- ${extra_head_data}
+${base.html_headstart()}
+<%block name="extra_head">
+### Leave this block alone.
+</%block>
+${template_hooks['extra_head']()}
</head>
<body>
- <h1 id="blog-title">
- <a href="${abs_link('/')}" title="${blog_title}" rel="home">${blog_title}</a>
- </h1>
- <%block name="belowtitle">
- %if len(translations) > 1:
- <small>
- ${messages("Also available in:")}&nbsp;
- ${base.html_translations()}
- </small>
- %endif
- </%block>
- <%block name="content"></%block>
- <small>${content_footer}</small>
- <!--Sidebar content-->
- <ul class="unstyled">
- %if license:
- <li>${license}
- %endif
- ${base.html_social()}
- ${base.html_navigation_links()}
- %if search_form:
- <li>${search_form}
- %endif
- </ul>
+ <div id="container">
+ ${header.html_header()}
+ <main id="content">
+ <%block name="content"></%block>
+ </main>
+ ${footer.html_footer()}
+ </div>
+ ${body_end}
+ ${template_hooks['body_end']()}
${base.late_load_js()}
- ${social_buttons_code}
</body>
</html>
diff --git a/nikola/data/themes/base/templates/base_footer.tmpl b/nikola/data/themes/base/templates/base_footer.tmpl
new file mode 100644
index 0000000..9a1c00f
--- /dev/null
+++ b/nikola/data/themes/base/templates/base_footer.tmpl
@@ -0,0 +1,11 @@
+## -*- coding: utf-8 -*-
+<%namespace name="base" file="base_helper.tmpl" import="*"/>
+
+<%def name="html_footer()">
+ %if content_footer:
+ <footer id="footer" role="contentinfo">
+ <p>${content_footer}</p>
+ ${template_hooks['page_footer']()}
+ </footer>
+ %endif
+</%def>
diff --git a/nikola/data/themes/base/templates/base_header.tmpl b/nikola/data/themes/base/templates/base_header.tmpl
new file mode 100644
index 0000000..0c6e12d
--- /dev/null
+++ b/nikola/data/themes/base/templates/base_header.tmpl
@@ -0,0 +1,66 @@
+## -*- coding: utf-8 -*-
+<%namespace name="base" file="base_helper.tmpl" import="*"/>
+
+<%def name="html_header()">
+ <header id="header" role="banner">
+ ${html_site_title()}
+ ${html_translation_header()}
+ ${html_navigation_links()}
+ %if search_form:
+ <div class="searchform" role="search">
+ ${search_form}
+ </div>
+ %endif
+ </header>
+ ${template_hooks['page_header']()}
+</%def>
+
+<%def name="html_site_title()">
+ <h1 id="brand"><a href="${abs_link('/')}" title="${blog_title}" rel="home">
+ %if logo_url:
+ <img src="${logo_url}" alt="${blog_title}" id="logo">
+ %endif
+
+ % if show_blog_title:
+ <span id="blog-title">${blog_title}</span>
+ % endif
+ </a></h1>
+</%def>
+
+<%def name="html_navigation_links()">
+ <nav id="menu" role="navigation">
+ <ul>
+ %for url, text in navigation_links[lang]:
+ % if isinstance(url, tuple):
+ <li> ${text}
+ <ul>
+ %for suburl, text in url:
+ % if rel_link(permalink, suburl) == "#":
+ <li class="active"><a href="${permalink}">${text}</a></li>
+ %else:
+ <li><a href="${suburl}">${text}</a></li>
+ %endif
+ %endfor
+ </ul>
+ % else:
+ % if rel_link(permalink, url) == "#":
+ <li class="active"><a href="${permalink}">${text}</a></li>
+ %else:
+ <li><a href="${url}">${text}</a></li>
+ %endif
+ % endif
+ %endfor
+ ${template_hooks['menu']()}
+ ${template_hooks['menu_alt']()}
+ </ul>
+ </nav>
+</%def>
+
+<%def name="html_translation_header()">
+ %if len(translations) > 1:
+ <div id="toptranslations">
+ <h2>${messages("Languages:")}</h2>
+ ${base.html_translations()}
+ </div>
+ %endif
+</%def>
diff --git a/nikola/data/themes/base/templates/base_helper.tmpl b/nikola/data/themes/base/templates/base_helper.tmpl
index 501c06e..beeff99 100644
--- a/nikola/data/themes/base/templates/base_helper.tmpl
+++ b/nikola/data/themes/base/templates/base_helper.tmpl
@@ -1,12 +1,67 @@
## -*- coding: utf-8 -*-
-<%def name="html_head()">
+
+<%def name="html_headstart()">
+<!DOCTYPE html>
+<html
+\
+% if use_open_graph or (twitter_card and twitter_card['use_twitter_cards']) or (comment_system == 'facebook'):
+prefix='\
+%if use_open_graph or (twitter_card and twitter_card['use_twitter_cards']):
+og: http://ogp.me/ns# \
+%endif
+%if use_open_graph:
+article: http://ogp.me/ns/article# \
+%endif
+%if comment_system == 'facebook':
+fb: http://ogp.me/ns/fb# \
+%endif
+'\
+%endif
+\
+% if is_rtl:
+dir="rtl" \
+% endif
+\
+lang="${lang}">
+ <head>
<meta charset="utf-8">
%if description:
<meta name="description" content="${description}">
%endif
- <meta name="author" content="${blog_author}">
+ <meta name="viewport" content="width=device-width">
<title>${title|striphtml} | ${blog_title|striphtml}</title>
+
+ ${html_stylesheets()}
+ ${html_feedlinks()}
+ %if permalink:
+ <link rel="canonical" href="${abs_link(permalink)}">
+ %endif
+
+ %if favicons:
+ %for name, file, size in favicons:
+ <link rel="${name}" href="${file}" sizes="${size}"/>
+ %endfor
+ %endif
+
+ % if comment_system == 'facebook':
+ <meta property="fb:app_id" content="${comment_system_id}">
+ % endif
+
${mathjax_config}
+ %if use_cdn:
+ <!--[if lt IE 9]><script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
+ %else:
+ <!--[if lt IE 9]><script src="/assets/js/html5.js"></script><![endif]-->
+ %endif
+
+ ${extra_head_data}
+</%def>
+
+<%def name="late_load_js()">
+ ${social_buttons_code}
+</%def>
+
+<%def name="html_stylesheets()">
%if use_bundles:
%if use_cdn:
<link href="/assets/css/all.css" rel="stylesheet" type="text/css">
@@ -16,20 +71,17 @@
%else:
<link href="/assets/css/rst.css" rel="stylesheet" type="text/css">
<link href="/assets/css/code.css" rel="stylesheet" type="text/css">
- <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"/>
+ <link href="/assets/css/theme.css" rel="stylesheet" type="text/css">
%if has_custom_css:
<link href="/assets/css/custom.css" rel="stylesheet" type="text/css">
%endif
%endif
- %if permalink:
- <link rel="canonical" href="${abs_link(permalink)}">
- %endif
- <!--[if lt IE 9]>
- <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
- <![endif]-->
+</%def>
+
+<%def name="html_feedlinks()">
%if rss_link:
${rss_link}
- %else:
+ %elif generate_rss:
%if len(translations) > 1:
%for language in translations:
<link rel="alternate" type="application/rss+xml" title="RSS (${language})" href="${_link('rss', None, language)}">
@@ -38,56 +90,14 @@
<link rel="alternate" type="application/rss+xml" title="RSS" href="${_link('rss', None)}">
%endif
%endif
- %if favicons:
- %for name, file, size in favicons:
- <link rel="${name}" href="${file}" sizes="${size}"/>
- %endfor
- %endif
- % if comment_system == 'facebook':
- <meta property="fb:app_id" content="${comment_system_id}">
- % endif
</%def>
-<%def name="late_load_js()">
-</%def>
-
-<%def name="html_social()">
- ${social_buttons_code}
-</%def>
-
-<!--FIXME: remove in v7 -->
-<%def name="html_sidebar_links()">
- ${html_navigation_links()}
-</%def>
-
-<%def name="html_navigation_links()">
- %for url, text in navigation_links[lang]:
- % if isinstance(url, tuple):
- <li> ${text}
- <ul>
- %for suburl, text in url:
- % if rel_link(permalink, suburl) == "#":
- <li class="active"><a href="${permalink}">${text}</a>
- %else:
- <li><a href="${suburl}">${text}</a>
- %endif
- %endfor
- </ul>
- % else:
- % if rel_link(permalink, url) == "#":
- <li class="active"><a href="${permalink}">${text}</a>
- %else:
- <li><a href="${url}">${text}</a>
- %endif
- % endif
- %endfor
-</%def>
-
-
<%def name="html_translations()">
+ <ul class="translations">
%for langname in translations.keys():
%if langname != lang:
- <a href="${_link("index", None, langname)}" rel="alternate" hreflang="${langname}">${messages("LANGUAGE", langname)}</a>
+ <li><a href="${_link("index", None, langname)}" rel="alternate" hreflang="${langname}">${messages("LANGUAGE", langname)}</a></li>
%endif
%endfor
+ </ul>
</%def>
diff --git a/nikola/data/themes/base/templates/comments_helper.tmpl b/nikola/data/themes/base/templates/comments_helper.tmpl
index d3a2704..1459888 100644
--- a/nikola/data/themes/base/templates/comments_helper.tmpl
+++ b/nikola/data/themes/base/templates/comments_helper.tmpl
@@ -1,12 +1,12 @@
## -*- coding: utf-8 -*-
-<%namespace name="disqus" file="disqus_helper.tmpl"/>
-<%namespace name="livefyre" file="livefyre_helper.tmpl"/>
-<%namespace name="intensedebate" file="intensedebate_helper.tmpl"/>
-<%namespace name="moot" file="moot_helper.tmpl"/>
-<%namespace name="googleplus" file="googleplus_helper.tmpl"/>
-<%namespace name="facebook" file="facebook_helper.tmpl"/>
-<%namespace name="isso" file="isso_helper.tmpl"/>
+<%namespace name="disqus" file="comments_helper_disqus.tmpl"/>
+<%namespace name="livefyre" file="comments_helper_livefyre.tmpl"/>
+<%namespace name="intensedebate" file="comments_helper_intensedebate.tmpl"/>
+<%namespace name="muut" file="comments_helper_muut.tmpl"/>
+<%namespace name="googleplus" file="comments_helper_googleplus.tmpl"/>
+<%namespace name="facebook" file="comments_helper_facebook.tmpl"/>
+<%namespace name="isso" file="comments_helper_isso.tmpl"/>
<%def name="comment_form(url, title, identifier)">
%if comment_system == 'disqus':
@@ -15,8 +15,8 @@
${livefyre.comment_form(url, title, identifier)}
% elif comment_system == 'intensedebate':
${intensedebate.comment_form(url, title, identifier)}
- % elif comment_system == 'moot':
- ${moot.comment_form(url, title, identifier)}
+ % elif comment_system == 'muut':
+ ${muut.comment_form(url, title, identifier)}
% elif comment_system == 'googleplus':
${googleplus.comment_form(url, title, identifier)}
% elif comment_system == 'facebook':
@@ -33,8 +33,8 @@
${livefyre.comment_link(link, identifier)}
% elif comment_system == 'intensedebate':
${intensedebate.comment_link(link, identifier)}
- % elif comment_system == 'moot':
- ${moot.comment_link(link, identifier)}
+ % elif comment_system == 'muut':
+ ${muut.comment_link(link, identifier)}
% elif comment_system == 'googleplus':
${googleplus.comment_link(link, identifier)}
% elif comment_system == 'facebook':
@@ -51,8 +51,8 @@
${livefyre.comment_link_script()}
% elif comment_system == 'intensedebate':
${intensedebate.comment_link_script()}
- % elif comment_system == 'moot':
- ${moot.comment_link_script()}
+ % elif comment_system == 'muut':
+ ${muut.comment_link_script()}
% elif comment_system == 'googleplus':
${googleplus.comment_link_script()}
% elif comment_system == 'facebook':
diff --git a/nikola/data/themes/base/templates/disqus_helper.tmpl b/nikola/data/themes/base/templates/comments_helper_disqus.tmpl
index 74187b0..8a94eaf 100644
--- a/nikola/data/themes/base/templates/disqus_helper.tmpl
+++ b/nikola/data/themes/base/templates/comments_helper_disqus.tmpl
@@ -25,15 +25,14 @@
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
- <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
- <a href="http://disqus.com" class="dsq-brlink" rel="nofollow">Comments powered by <span class="logo-disqus">Disqus</span></a>
+ <noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
+ <a href="//disqus.com" class="dsq-brlink" rel="nofollow">Comments powered by <span class="logo-disqus">Disqus</span></a>
%endif
</%def>
<%def name="comment_link(link, identifier)">
- <p>
%if comment_system_id:
- <a href="${link}#disqus_thread" data-disqus-identifier="${identifier}">Comments</a>
+ <a href="${link}#disqus_thread" data-disqus-identifier="${identifier}">Comments</a>
%endif
</%def>
@@ -43,16 +42,3 @@
<script>var disqus_shortname="${comment_system_id}";(function(){var a=document.createElement("script");a.async=true;a.src="//"+disqus_shortname+".disqus.com/count.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a)}());</script>
%endif
</%def>
-
-## FIXME: remove aliases in v7
-<%def name="html_disqus(url, title, identifier)">
- ${comment_form(url, title, identifier)}
-</%def>
-
-<%def name="html_disqus_link(link, identifier)">
- ${comment_link(link, identifier)}
-</%def>
-
-<%def name="html_disqus_script()">
- ${comment_link_script()}
-</%def>
diff --git a/nikola/data/themes/base/templates/facebook_helper.tmpl b/nikola/data/themes/base/templates/comments_helper_facebook.tmpl
index d6059a1..d6059a1 100644
--- a/nikola/data/themes/base/templates/facebook_helper.tmpl
+++ b/nikola/data/themes/base/templates/comments_helper_facebook.tmpl
diff --git a/nikola/data/themes/base/templates/googleplus_helper.tmpl b/nikola/data/themes/base/templates/comments_helper_googleplus.tmpl
index 5a5c4d7..5a5c4d7 100644
--- a/nikola/data/themes/base/templates/googleplus_helper.tmpl
+++ b/nikola/data/themes/base/templates/comments_helper_googleplus.tmpl
diff --git a/nikola/data/themes/base/templates/intensedebate_helper.tmpl b/nikola/data/themes/base/templates/comments_helper_intensedebate.tmpl
index 6462f74..c47b6c7 100644
--- a/nikola/data/themes/base/templates/intensedebate_helper.tmpl
+++ b/nikola/data/themes/base/templates/comments_helper_intensedebate.tmpl
@@ -6,7 +6,7 @@ var idcomments_post_id = "${identifier}";
var idcomments_post_url = "${url}";
</script>
<span id="IDCommentsPostTitle" style="display:none"></span>
-<script type='text/javascript' src='http://www.intensedebate.com/js/genericCommentWrapperV2.js'></script>
+<script src='http://www.intensedebate.com/js/genericCommentWrapperV2.js'></script>
</script>
</%def>
@@ -17,7 +17,7 @@ var idcomments_acct = '${comment_system_id}';
var idcomments_post_id = "${identifier}";
var idcomments_post_url = "${link}";
</script>
-<script type="text/javascript" src="http://www.intensedebate.com/js/genericLinkWrapperV2.js"></script>
+<script src="http://www.intensedebate.com/js/genericLinkWrapperV2.js"></script>
</a>
</%def>
diff --git a/nikola/data/themes/base/templates/isso_helper.tmpl b/nikola/data/themes/base/templates/comments_helper_isso.tmpl
index 8dc95f5..8dc95f5 100644
--- a/nikola/data/themes/base/templates/isso_helper.tmpl
+++ b/nikola/data/themes/base/templates/comments_helper_isso.tmpl
diff --git a/nikola/data/themes/base/templates/livefyre_helper.tmpl b/nikola/data/themes/base/templates/comments_helper_livefyre.tmpl
index 6916459..68d99e5 100644
--- a/nikola/data/themes/base/templates/livefyre_helper.tmpl
+++ b/nikola/data/themes/base/templates/comments_helper_livefyre.tmpl
@@ -1,8 +1,8 @@
## -*- coding: utf-8 -*-
<%def name="comment_form(url, title, identifier)">
<div id="livefyre-comments"></div>
-<script type="text/javascript" src="http://zor.livefyre.com/wjs/v3.0/javascripts/livefyre.js"></script>
-<script type="text/javascript">
+<script src="http://zor.livefyre.com/wjs/v3.0/javascripts/livefyre.js"></script>
+<script>
(function () {
var articleId = "${identifier}";
fyre.conv.load({}, [{
@@ -21,17 +21,13 @@
</%def>
<%def name="comment_link(link, identifier)">
- <p>
<a href="${link}">
<span class="livefyre-commentcount" data-lf-site-id="${comment_system_id}" data-lf-article-id="${identifier}">
0 Comments
- </span></a>
+ </span>
</%def>
<%def name="comment_link_script()">
-<script
- type="text/javascript"
- src="http://zor.livefyre.com/wjs/v1.0/javascripts/CommentCount.js">
-</script>
+<script src="http://zor.livefyre.com/wjs/v1.0/javascripts/CommentCount.js"></script>
</%def>
diff --git a/nikola/data/themes/base/templates/mustache-comment-form.tmpl b/nikola/data/themes/base/templates/comments_helper_mustache.tmpl
index 593d0aa..593d0aa 100644
--- a/nikola/data/themes/base/templates/mustache-comment-form.tmpl
+++ b/nikola/data/themes/base/templates/comments_helper_mustache.tmpl
diff --git a/nikola/data/themes/base/templates/moot_helper.tmpl b/nikola/data/themes/base/templates/comments_helper_muut.tmpl
index 951553e..94532d9 100644
--- a/nikola/data/themes/base/templates/moot_helper.tmpl
+++ b/nikola/data/themes/base/templates/comments_helper_muut.tmpl
@@ -1,7 +1,7 @@
## -*- coding: utf-8 -*-
<%def name="comment_form(url, title, identifier)">
- <a class="moot" href="https://moot.it/i/${comment_system_id}/${identifier}">${comment_system_id} forums</a>
+ <a class="muut" href="https://muut.com/i/${comment_system_id}/${identifier}">${comment_system_id} forums</a>
</%def>
<%def name="comment_link(link, identifier)">
@@ -9,5 +9,5 @@
<%def name="comment_link_script()">
-<script src="https://cdn.moot.it/1/moot.min.js"></script>
+<script src="//cdn.muut.com/1/moot.min.js"></script>
</%def>
diff --git a/nikola/data/themes/base/templates/crumbs.tmpl b/nikola/data/themes/base/templates/crumbs.tmpl
index 8fbafcf..de8e570 100644
--- a/nikola/data/themes/base/templates/crumbs.tmpl
+++ b/nikola/data/themes/base/templates/crumbs.tmpl
@@ -2,10 +2,12 @@
<%def name="bar(crumbs)">
%if crumbs:
+<nav class="breadcrumbs">
<ul class="breadcrumb">
% for link, text in crumbs:
<li><a href="${link}">${text}</a></li>
% endfor
</ul>
+</nav>
%endif
</%def>
diff --git a/nikola/data/themes/base/templates/gallery.tmpl b/nikola/data/themes/base/templates/gallery.tmpl
index 731a75a..ca9da05 100644
--- a/nikola/data/themes/base/templates/gallery.tmpl
+++ b/nikola/data/themes/base/templates/gallery.tmpl
@@ -9,9 +9,9 @@
%if title:
<h1>${title}</h1>
%endif
- %if text:
+ %if post:
<p>
- ${text}
+ ${post.text()}
</p>
%endif
%if folders:
@@ -30,7 +30,7 @@
%endfor
</ul>
%endif
-%if enable_comments:
+%if site_has_comments and enable_comments:
${comments.comment_form(None, permalink, title)}
%endif
</%block>
diff --git a/nikola/data/themes/base/templates/index.tmpl b/nikola/data/themes/base/templates/index.tmpl
index 1a280b0..e833eb0 100644
--- a/nikola/data/themes/base/templates/index.tmpl
+++ b/nikola/data/themes/base/templates/index.tmpl
@@ -2,28 +2,33 @@
<%namespace name="helper" file="index_helper.tmpl"/>
<%namespace name="comments" file="comments_helper.tmpl"/>
<%inherit file="base.tmpl"/>
+
<%block name="content">
- % for post in posts:
- <article class="postbox h-entry post-${post.meta('type')}">
- <h1 class="p-name"><a href="${post.permalink()}" class="u-url">${post.title()}</a>
- <small>&nbsp;&nbsp;
- ${messages("Posted:")} <time class="published dt-published" datetime="${post.date.isoformat()}">${post.formatted_date(date_format)}</time>
- </small></h1>
- <hr>
- %if index_teasers:
- <div class="p-summary">
- ${post.text(teaser_only=True)}
- %else:
- <div class="e-content">
- ${post.text(teaser_only=False)}
- %endif
+<div class="postindex">
+% for post in posts:
+ <article class="h-entry post-${post.meta('type')}">
+ <header>
+ <h1 class="p-name entry-title"><a href="${post.permalink()}" class="u-url">${post.title()}</h1></a>
+ <div class="metadata">
+ <p class="byline author vcard"><span class="byline-name fn">${post.author()}</span></p>
+ <p class="dateline"><a href="${post.permalink()}" rel="bookmark"><time class="published dt-published" datetime="${post.date.isoformat()}" itemprop="datePublished" title="${messages("Publication date")}">${post.formatted_date(date_format)}</time></a></p>
+ % if not post.meta('nocomments') and site_has_comments:
+ <p class="commentline">${comments.comment_link(post.permalink(), post._base_path)}
+ % endif
</div>
- % if not post.meta('nocomments'):
- ${comments.comment_link(post.permalink(), post._base_path)}
- % endif
- </article>
- % endfor
- ${helper.html_pager()}
- ${comments.comment_link_script()}
- ${helper.mathjax_script(posts)}
+ </header>
+ %if index_teasers:
+ <div class="p-summary entry-summary">
+ ${post.text(teaser_only=True)}
+ %else:
+ <div class="e-content entry-content">
+ ${post.text(teaser_only=False)}
+ %endif
+ </div>
+ </article>
+% endfor
+</div>
+${helper.html_pager()}
+${comments.comment_link_script()}
+${helper.mathjax_script(posts)}
</%block>
diff --git a/nikola/data/themes/base/templates/index_helper.tmpl b/nikola/data/themes/base/templates/index_helper.tmpl
index c925559..9331b93 100644
--- a/nikola/data/themes/base/templates/index_helper.tmpl
+++ b/nikola/data/themes/base/templates/index_helper.tmpl
@@ -1,30 +1,27 @@
## -*- coding: utf-8 -*-
<%def name="html_pager()">
%if prevlink or nextlink:
- <div>
+ <nav class="postindexpager">
<ul class="pager">
%if prevlink:
<li class="previous">
- <a href="${prevlink}" rel="prev">&larr; ${messages("Newer posts")}</a>
+ <a href="${prevlink}" rel="prev">${messages("Newer posts")}</a>
</li>
%endif
%if nextlink:
<li class="next">
- <a href="${nextlink}" rel="next">${messages("Older posts")} &rarr;</a>
+ <a href="${nextlink}" rel="next">${messages("Older posts")}</a>
</li>
%endif
</ul>
- </div>
+ </nav>
%endif
</%def>
<%def name="mathjax_script(posts)">
%if any(post.is_mathjax for post in posts):
<script type="text/x-mathjax-config">
- MathJax.Hub.Config({
- tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}
- });
- </script>
+ MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});</script>
<script src="/assets/js/mathjax.js"></script>
%endif
</%def>
diff --git a/nikola/data/themes/base/templates/list.tmpl b/nikola/data/themes/base/templates/list.tmpl
index 4136eb9..4082516 100644
--- a/nikola/data/themes/base/templates/list.tmpl
+++ b/nikola/data/themes/base/templates/list.tmpl
@@ -1,16 +1,19 @@
## -*- coding: utf-8 -*-
<%inherit file="base.tmpl"/>
+
<%block name="content">
- <!--Body content-->
- <div class="postbox">
+<article class="listpage">
+ <header>
<h1>${title}</h1>
- %if items:
- <ul class="unstyled">
- % for text, link in items:
- <li><a href="${link}">${text}</a>
- % endfor
- </ul>
- %endif
- </div>
- <!--End of body content-->
+ </header>
+ %if items:
+ <ul class="postlist">
+ % for text, link in items:
+ <li><a href="${link}">${text}</a>
+ % endfor
+ </ul>
+ %else:
+ <p>${messages("Nothing found.")}</p>
+ %endif
+</article>
</%block>
diff --git a/nikola/data/themes/base/templates/list_post.tmpl b/nikola/data/themes/base/templates/list_post.tmpl
index b27f230..0ef164f 100644
--- a/nikola/data/themes/base/templates/list_post.tmpl
+++ b/nikola/data/themes/base/templates/list_post.tmpl
@@ -1,16 +1,19 @@
## -*- coding: utf-8 -*-
<%inherit file="base.tmpl"/>
+
<%block name="content">
- <!--Body content-->
- <div class="postbox">
+<article class="listpage">
+ <header>
<h1>${title}</h1>
- %if posts:
- <ul class="unstyled">
- % for post in posts:
- <li><a href="${post.permalink()}">[${post.formatted_date(date_format)}] ${post.title()}</a>
- % endfor
- </ul>
- %endif
- </div>
- <!--End of body content-->
+ </header>
+ %if posts:
+ <ul class="postlist">
+ % for post in posts:
+ <li><a href="${post.permalink()}" class="listtitle">${post.title()}</a> <time class="listdate" datetime="${post.date.isoformat()}" title="${messages("Publication date")}">${post.formatted_date(date_format)}</time></li>
+ % endfor
+ </ul>
+ %else:
+ <p>${messages("No posts found.")}</p>
+ %endif
+</article>
</%block>
diff --git a/nikola/data/themes/base/templates/listing.tmpl b/nikola/data/themes/base/templates/listing.tmpl
index 0662360..e0bf91b 100644
--- a/nikola/data/themes/base/templates/listing.tmpl
+++ b/nikola/data/themes/base/templates/listing.tmpl
@@ -4,7 +4,7 @@
<%block name="content">
${ui.bar(crumbs)}
%if folders or files:
-<ul class="unstyled">
+<ul>
% for name in folders:
<li><a href="${name}"><i class="icon-folder-open"></i> ${name}</a>
% endfor
@@ -16,4 +16,8 @@ ${ui.bar(crumbs)}
% if code:
${code}
% endif
+% if source_link:
+ <p class="sourceline"><a href="${source_link}" id="sourcelink">${messages("Source")}</a></p>
+% endif
</%block>
+
diff --git a/nikola/data/themes/base/templates/post.tmpl b/nikola/data/themes/base/templates/post.tmpl
index 981fd97..0babb2b 100644
--- a/nikola/data/themes/base/templates/post.tmpl
+++ b/nikola/data/themes/base/templates/post.tmpl
@@ -1,42 +1,39 @@
## -*- coding: utf-8 -*-
<%namespace name="helper" file="post_helper.tmpl"/>
+<%namespace name="pheader" file="post_header.tmpl"/>
<%namespace name="comments" file="comments_helper.tmpl"/>
<%inherit file="base.tmpl"/>
+
<%block name="extra_head">
-${helper.twitter_card_information(post)}
-% if post.meta('keywords'):
- <meta name="keywords" content="${post.meta('keywords')|h}">
-% endif
-${helper.meta_translations(post)}
+ ${parent.extra_head()}
+ % if post.meta('keywords'):
+ <meta name="keywords" content="${post.meta('keywords')|h}">
+ % endif
+ <meta name="author" content="${post.author()}">
+ ${helper.open_graph_metadata(post)}
+ ${helper.twitter_card_information(post)}
+ ${helper.meta_translations(post)}
</%block>
+
<%block name="content">
- <article class="postbox post-${post.meta('type')}">
- <div class="h-entry" itemscope="itemscope" itemtype="http://schema.org/Article">
- ${helper.html_title()}
- <hr>
- <small>
- ${messages("Posted:")} <time class="published dt-published" datetime="${post.date.isoformat()}" itemprop="datePublished">${post.formatted_date(date_format)}</time>
- ${helper.html_translations(post)}
- ${helper.html_tags(post)}
- &nbsp;&nbsp;|&nbsp;&nbsp;
- <%block name="sourcelink">
- % if not post.meta('password'):
- <a href="${post.source_link()}" id="sourcelink">${messages("Source")}</a>
- % endif
- </%block>
- </small>
- <hr>
- <div class="e-content" itemprop="articleBody text">
+<article class="post-${post.meta('type')} h-entry hentry postpage" itemscope="itemscope" itemtype="http://schema.org/Article">
+ ${pheader.html_post_header()}
+ <div class="e-content entry-content" itemprop="articleBody text">
${post.text()}
</div>
- %if post.description():
- <meta content="${post.description()}" itemprop="description">
- %endif
- </div>
+ <aside class="postpromonav">
+ <nav>
+ ${helper.html_tags(post)}
${helper.html_pager(post)}
- % if not post.meta('nocomments'):
+ </nav>
+ </aside>
+ % if not post.meta('nocomments') and site_has_comments:
+ <section class="comments">
+ <h2>${messages("Comments")}</h2>
${comments.comment_form(post.permalink(absolute=True), post.title(), post._base_path)}
+ </section>
% endif
${helper.mathjax_script(post)}
- </article>
+</article>
+${comments.comment_link_script()}
</%block>
diff --git a/nikola/data/themes/base/templates/post_header.tmpl b/nikola/data/themes/base/templates/post_header.tmpl
new file mode 100644
index 0000000..c848186
--- /dev/null
+++ b/nikola/data/themes/base/templates/post_header.tmpl
@@ -0,0 +1,49 @@
+## -*- coding: utf-8 -*-
+<%namespace name="helper" file="post_helper.tmpl"/>
+<%namespace name="comments" file="comments_helper.tmpl"/>
+
+<%def name="html_title()">
+%if title and not post.meta('hidetitle'):
+ <h1 class="p-name entry-title" itemprop="headline name"><a href="${post.permalink()}" class="u-url">${title|h}</a></h1>
+%endif
+</%def>
+
+<%def name="html_translations(post)">
+ % if len(translations) > 1:
+ <div class="metadata posttranslations translations">
+ <h3 class="posttranslations-intro">${messages("Also available in:")}</h3>
+ % for langname in translations.keys():
+ % if langname != lang and post.is_translation_available(langname):
+ <p><a href="${post.permalink(langname)}" rel="alternate" hreflang="${langname}">${messages("LANGUAGE", langname)}</a></p>
+ % endif
+ % endfor
+ </div>
+ % endif
+</%def>
+
+<%def name="html_sourcelink()">
+ % if show_sourcelink:
+ <p class="sourceline"><a href="${post.source_link()}" id="sourcelink">${messages("Source")}</a></p>
+ % endif
+</%def>
+
+<%def name="html_post_header()">
+ <header>
+ ${html_title()}
+ <div class="metadata">
+ <p class="byline author vcard"><span class="byline-name fn">${post.author()}</span></p>
+ <p class="dateline"><a href="${post.permalink()}" rel="bookmark"><time class="published dt-published" datetime="${post.date.isoformat()}" itemprop="datePublished" title="${messages("Publication date")}">${post.formatted_date(date_format)}</time></a></p>
+ % if not post.meta('nocomments') and site_has_comments:
+ <p class="commentline">${comments.comment_link(post.permalink(), post._base_path)}
+ % endif
+ ${html_sourcelink()}
+ % if post.meta('link'):
+ <p><a href='${post.meta('link')}'>${messages("Original site")}</a></p>
+ % endif
+ %if post.description():
+ <meta name="description" itemprop="description" content="${post.description()}">
+ %endif
+ </div>
+ ${html_translations(post)}
+ </header>
+</%def>
diff --git a/nikola/data/themes/base/templates/post_helper.tmpl b/nikola/data/themes/base/templates/post_helper.tmpl
index 391350d..85ba378 100644
--- a/nikola/data/themes/base/templates/post_helper.tmpl
+++ b/nikola/data/themes/base/templates/post_helper.tmpl
@@ -1,22 +1,4 @@
## -*- coding: utf-8 -*-
-<%def name="html_title()">
- <h1 class="p-name" itemprop="headline name">${title|h}</h1>
- % if link:
- <p><a href='${link}'>${messages("Original site")}</a></p>
- % endif
-</%def>
-
-
-<%def name="html_translations(post)">
- %if len(translations) > 1:
- %for langname in translations.keys():
- %if langname != lang and post.is_translation_available(langname):
- &nbsp;&nbsp;|&nbsp;&nbsp;
- <a href="${post.permalink(langname)}" rel="alternate" hreflang="${langname}">${messages("Read in English", langname)}</a>
- %endif
- %endfor
- %endif
-</%def>
<%def name="meta_translations(post)">
%if len(translations) > 1:
@@ -28,18 +10,13 @@
%endif
</%def>
-<%def name="html_list_tags(post)" buffered="True">
- <span itemprop="keywords">
- %for tag in post.tags:
- <a class="tag p-category" href="${_link('tag', tag)}"><span class="badge badge-info">${tag}</span></a>
- %endfor
- </span>
-</%def>
-
<%def name="html_tags(post)">
%if post.tags:
- &nbsp;&nbsp;|&nbsp;&nbsp;
- ${formatmsg(messages("More posts about %s"), html_list_tags(post))}
+ <ul itemprop="keywords" class="tags">
+ %for tag in post.tags:
+ <li><a class="tag p-category" href="${_link('tag', tag)}" rel="tag">${tag}</a></li>
+ %endfor
+ </ul>
%endif
</%def>
@@ -48,22 +25,35 @@
<ul class="pager">
%if post.prev_post:
<li class="previous">
- <a href="${post.prev_post.permalink()}" rel="prev">&larr; ${messages("Previous post")}</a>
+ <a href="${post.prev_post.permalink()}" rel="prev" title="${post.prev_post.title()}">${messages("Previous post")}</a>
</li>
%endif
%if post.next_post:
<li class="next">
- <a href="${post.next_post.permalink()}" rel="next">${messages("Next post")} &rarr;</a>
+ <a href="${post.next_post.permalink()}" rel="next" title="${post.next_post.title()}">${messages("Next post")}</a>
</li>
%endif
</ul>
%endif
</%def>
+<%def name="open_graph_metadata(post)">
+ %if use_open_graph:
+ <meta name="og:title" content="${post.title()[:70]|h}">
+ <meta name="og:url" content="${abs_link(permalink)}">
+ %if post.description():
+ <meta name="og:description" content="${post.description()[:200]|h}">
+ %else:
+ <meta name="og:description" content="${post.text(strip_html=True)[:200]|h}">
+ %endif
+ <meta name="og:site_name" content="${blog_title|striphtml}">
+ <meta name="og:type" content="article">
+ %endif
+</%def>
+
<%def name="twitter_card_information(post)">
%if twitter_card and twitter_card['use_twitter_cards']:
<meta name="twitter:card" content="${twitter_card.get('card', 'summary')|h}">
- <meta name="og:url" content="${post.permalink(absolute=True)}">
%if 'site:id' in twitter_card:
<meta name="twitter:site:id" content="${twitter_card['site:id']}">
%elif 'site' in twitter_card:
@@ -74,22 +64,13 @@
%elif 'creator' in twitter_card:
<meta name="twitter:creator" content="${twitter_card['creator']}">
%endif
- <meta name="og:title" content="${post.title()[:70]|h}">
- %if post.description():
- <meta name="og:description" content="${post.description()[:200]|h}">
- %else:
- <meta name="og:description" content="${post.text(strip_html=True)[:200]|h}">
- %endif
%endif
</%def>
<%def name="mathjax_script(post)">
%if post.is_mathjax:
<script type="text/x-mathjax-config">
- MathJax.Hub.Config({
- tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}
- });
- </script>
+ MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});</script>
<script src="/assets/js/mathjax.js"></script>
%endif
</%def>
diff --git a/nikola/data/themes/base/templates/post_list_directive.tmpl b/nikola/data/themes/base/templates/post_list_directive.tmpl
index b31d242..d9166e9 100644
--- a/nikola/data/themes/base/templates/post_list_directive.tmpl
+++ b/nikola/data/themes/base/templates/post_list_directive.tmpl
@@ -1,4 +1,5 @@
## -*- coding: utf-8 -*-
+<%block name="content">
<!-- Begin post-list ${post_list_id} -->
<div id="${post_list_id}" class="post-list">
%if posts:
@@ -14,3 +15,4 @@
%endif
</div>
<!-- End post-list ${post_list_id} -->
+</%block>
diff --git a/nikola/data/themes/base/templates/slides.tmpl b/nikola/data/themes/base/templates/slides.tmpl
index 14983ad..048fb7e 100644
--- a/nikola/data/themes/base/templates/slides.tmpl
+++ b/nikola/data/themes/base/templates/slides.tmpl
@@ -1,6 +1,7 @@
+<%block name="content">
<div id="${carousel_id}" class="carousel slide">
<ol class="carousel-indicators">
- % for i in range(len(content)):
+ % for i in range(len(slides_content)):
% if i == 0:
<li data-target="#${carousel_id}" data-slide-to="${i}" class="active"></li>
% else:
@@ -9,7 +10,7 @@
% endfor
</ol>
<div class="carousel-inner">
- % for i, image in enumerate(content):
+ % for i, image in enumerate(slides_content):
% if i == 0:
<div class="item active"><img src="${image}" alt="" style="margin: 0 auto 0 auto;"></div>
% else:
@@ -20,3 +21,4 @@
<a class="left carousel-control" href="#${carousel_id}" data-slide="prev">&lsaquo;</a>
<a class="right carousel-control" href="#${carousel_id}" data-slide="next">&rsaquo;</a>
</div>
+</%block>
diff --git a/nikola/data/themes/base/templates/story.tmpl b/nikola/data/themes/base/templates/story.tmpl
index 7406f05..e3e3054 100644
--- a/nikola/data/themes/base/templates/story.tmpl
+++ b/nikola/data/themes/base/templates/story.tmpl
@@ -1,16 +1,37 @@
## -*- coding: utf-8 -*-
-<%inherit file="post.tmpl"/>
<%namespace name="helper" file="post_helper.tmpl"/>
+<%namespace name="pheader" file="post_header.tmpl"/>
<%namespace name="comments" file="comments_helper.tmpl"/>
+<%inherit file="post.tmpl"/>
+
<%block name="extra_head">
-${helper.twitter_card_information(post)}
+ ${parent.extra_head()}
+ % if post.meta('keywords'):
+ <meta name="keywords" content="${post.meta('keywords')|h}">
+ % endif
+ <meta name="author" content="${post.author()}">
+ ${helper.open_graph_metadata(post)}
+ ${helper.twitter_card_information(post)}
+ ${helper.meta_translations(post)}
+ %if post.description():
+ <meta name="description" itemprop="description" content="${post.description()}">
+ %endif
</%block>
+
<%block name="content">
-%if title and not post.meta('hidetitle'):
- <h1>${title}</h1>
-%endif
+<article class="storypage" itemscope="itemscope" itemtype="http://schema.org/Article">
+ <header>
+ ${pheader.html_title()}
+ ${pheader.html_translations(post)}
+ </header>
+ <div itemprop="articleBody text">
${post.text()}
-%if enable_comments and not post.meta('nocomments'):
- ${comments.comment_form(post.permalink(absolute=True), post.title(), post.base_path)}
-%endif
+ </div>
+ %if site_has_comments and enable_comments and not post.meta('nocomments'):
+ <section class="comments">
+ <h2>${messages("Comments")}</h2>
+ ${comments.comment_form(post.permalink(absolute=True), post.title(), post.base_path)}
+ </section>
+ %endif
+</article>
</%block>
diff --git a/nikola/data/themes/base/templates/tag.tmpl b/nikola/data/themes/base/templates/tag.tmpl
index 43afd54..bff82c2 100644
--- a/nikola/data/themes/base/templates/tag.tmpl
+++ b/nikola/data/themes/base/templates/tag.tmpl
@@ -1,34 +1,40 @@
## -*- coding: utf-8 -*-
<%inherit file="list_post.tmpl"/>
+
<%block name="extra_head">
- %if len(translations) > 1:
+ ${parent.extra_head()}
+ %if len(translations) > 1 and generate_rss:
%for language in translations:
<link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for ${kind} ${tag} (${language})" href="${_link(kind + "_rss", tag, language)}">
%endfor
- %else:
+ %elif generate_rss:
<link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for ${kind} ${tag}" href="${_link(kind + "_rss", tag)}">
%endif
</%block>
+
<%block name="content">
- <!--Body content-->
- <div class="postbox">
+<article class="tagpage">
+ <header>
<h1>${title}</h1>
- %if len(translations) > 1:
- %for language in translations:
- <a href="${_link(kind + "_rss", tag, language)}">RSS (${language})</a>&nbsp;
- %endfor
- %else:
- <a href="${_link(kind + "_rss", tag)}">RSS</a>
- %endif
- <br>
- %if posts:
- <ul class="unstyled">
- % for post in posts:
- <li><a href="${post.permalink()}">[${post.formatted_date(date_format)}] ${post.title()}</a>
- % endfor
- </ul>
- %endif
+ <div class="metadata">
+ %if len(translations) > 1 and generate_rss:
+ %for language in translations:
+ <p class="feedlink">
+ <a href="${_link(kind + "_rss", tag, language)}" hreflang="${language}" type="application/rss+xml">${messages('RSS feed', language)} (${language})</a>&nbsp;
+ </p>
+ %endfor
+ %elif generate_rss:
+ <p class="feedlink"><a href="${_link(kind + "_rss", tag)}" type="application/rss+xml">${messages('RSS feed')}</a></p>
+ %endif
</div>
- <!--End of body content-->
+ </header>
+ %if posts:
+ <ul class="postlist">
+ % for post in posts:
+ <li><a href="${post.permalink()}" class="listtitle">${post.title()}</a> <time class="listdate" datetime="${post.date.isoformat()}" title="${messages("Publication date")}">${post.formatted_date(date_format)}</time></li>
+ % endfor
+ </ul>
+ %endif
+</article>
</%block>
diff --git a/nikola/data/themes/base/templates/tags.tmpl b/nikola/data/themes/base/templates/tags.tmpl
index 6c8c5e9..3e0c4b4 100644
--- a/nikola/data/themes/base/templates/tags.tmpl
+++ b/nikola/data/themes/base/templates/tags.tmpl
@@ -1,10 +1,14 @@
## -*- coding: utf-8 -*-
<%inherit file="base.tmpl"/>
+
<%block name="content">
- <h1>${title}</h1>
+<article class="tagindex">
+ <header>
+ <h1>${title}</h1>
+ </header>
% if cat_items:
<h2>${messages("Categories")}</h2>
- <ul class="unstyled bricks">
+ <ul class="postlist">
% for text, link in cat_items:
% if text:
<li><a class="reference" href="${link}">${text}</a></li>
@@ -16,10 +20,11 @@
% endif
%endif
% if items:
- <ul class="unstyled bricks">
+ <ul class="postlist">
% for text, link in items:
- <li><a class="reference" href="${link}">${text}</a></li>
+ <li><a class="reference listtitle" href="${link}">${text}</a></li>
% endfor
</ul>
% endif
+</article>
</%block>
diff --git a/nikola/data/themes/bootstrap-jinja/AUTHORS.txt b/nikola/data/themes/bootstrap-jinja/AUTHORS.txt
new file mode 100644
index 0000000..043d497
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/AUTHORS.txt
@@ -0,0 +1 @@
+Roberto Alsina <https://github.com/ralsina>
diff --git a/nikola/data/themes/bootstrap-jinja/README.md b/nikola/data/themes/bootstrap-jinja/README.md
new file mode 100644
index 0000000..5340fe2
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/README.md
@@ -0,0 +1,23 @@
+A "website-done-with-bootstrap" theme, so to speak.
+
+Has a fixed navigation bar at top that displays the NAVIGATION_LINKS
+setting and supports nested menus.
+
+This theme is used in Nikola's website: http://getnikola.com
+
+Important: To fit in the bootstrap navigation bar, the search form needs the
+navbar-form and pull-left CSS classes applied. Here is an example with Nikola's
+default duckduckgo search form:
+
+ SEARCH_FORM = """
+ <!-- Custom search -->
+ <form method="get" id="search" action="http://duckduckgo.com/" class="navbar-form pull-left">
+ <input type="hidden" name="sites" value="%s"/>
+ <input type="hidden" name="k8" value="#444444"/>
+ <input type="hidden" name="k9" value="#D51920"/>
+ <input type="hidden" name="kt" value="h"/>
+ <input type="text" name="q" maxlength="255" placeholder="Search&hellip;" class="span2" style="margin-top: 4px;"/>
+ <input type="submit" value="DuckDuckGo Search" style="visibility: hidden;" />
+ </form>
+ <!-- End of custom search -->
+ """ % SITE_URL
diff --git a/nikola/data/themes/bootstrap-jinja/assets/css/colorbox.css b/nikola/data/themes/bootstrap-jinja/assets/css/colorbox.css
new file mode 120000
index 0000000..5f8b3b0
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/css/colorbox.css
@@ -0,0 +1 @@
+../../../../../../bower_components/jquery-colorbox/example3/colorbox.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/css/images/controls.png b/nikola/data/themes/bootstrap-jinja/assets/css/images/controls.png
new file mode 120000
index 0000000..841a726
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/css/images/controls.png
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/example3/images/controls.png \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/css/images/loading.gif b/nikola/data/themes/bootstrap-jinja/assets/css/images/loading.gif
new file mode 120000
index 0000000..b192a75
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/css/images/loading.gif
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/example3/images/loading.gif \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/css/theme.css b/nikola/data/themes/bootstrap-jinja/assets/css/theme.css
new file mode 120000
index 0000000..7566a80
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/css/theme.css
@@ -0,0 +1 @@
+../../../bootstrap/assets/css/theme.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ar.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ar.js
new file mode 120000
index 0000000..f83073f
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ar.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-ar.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-bg.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-bg.js
new file mode 120000
index 0000000..bafc4e0
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-bg.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-bg.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ca.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ca.js
new file mode 120000
index 0000000..a749232
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ca.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-ca.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-cs.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-cs.js
new file mode 120000
index 0000000..e4a595c
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-cs.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-cs.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-da.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-da.js
new file mode 120000
index 0000000..1e9a1d6
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-da.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-da.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-de.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-de.js
new file mode 120000
index 0000000..748f53b
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-de.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-de.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-es.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-es.js
new file mode 120000
index 0000000..1154fb5
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-es.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-es.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-et.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-et.js
new file mode 120000
index 0000000..483e192
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-et.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-et.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fa.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fa.js
new file mode 120000
index 0000000..a30b13c
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fa.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-fa.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fi.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fi.js
new file mode 120000
index 0000000..2a7e8ad
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fi.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-fi.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fr.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fr.js
new file mode 120000
index 0000000..e359290
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-fr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-fr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-gl.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-gl.js
new file mode 120000
index 0000000..04fa276
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-gl.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-gl.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-gr.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-gr.js
new file mode 120000
index 0000000..d8105ab
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-gr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-gr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-he.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-he.js
new file mode 120000
index 0000000..72dddf5
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-he.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-he.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-hr.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-hr.js
new file mode 120000
index 0000000..34aa3c0
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-hr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-hr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-hu.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-hu.js
new file mode 120000
index 0000000..a87f03c
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-hu.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-hu.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-id.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-id.js
new file mode 120000
index 0000000..31053b8
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-id.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-id.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-it.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-it.js
new file mode 120000
index 0000000..aad9d22
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-it.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-it.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ja.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ja.js
new file mode 120000
index 0000000..3ea27c2
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ja.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-ja.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-kr.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-kr.js
new file mode 120000
index 0000000..3e23b4a
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-kr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-kr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-lt.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-lt.js
new file mode 120000
index 0000000..374b9bb
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-lt.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-lt.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-lv.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-lv.js
new file mode 120000
index 0000000..101b476
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-lv.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-lv.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-my.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-my.js
new file mode 120000
index 0000000..8e14f15
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-my.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-my.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-nl.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-nl.js
new file mode 120000
index 0000000..2d03d48
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-nl.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-nl.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-no.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-no.js
new file mode 120000
index 0000000..9af0ba7
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-no.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-no.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-pl.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-pl.js
new file mode 120000
index 0000000..34f8ab1
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-pl.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-pl.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-pt-br.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-pt-br.js
new file mode 120000
index 0000000..76f289e
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-pt-br.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-pt-br.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ro.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ro.js
new file mode 120000
index 0000000..555f2e6
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ro.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-ro.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ru.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ru.js
new file mode 120000
index 0000000..bac4855
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-ru.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-ru.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-si.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-si.js
new file mode 120000
index 0000000..65b0492
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-si.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-si.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sk.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sk.js
new file mode 120000
index 0000000..99859fd
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sk.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-sk.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sr.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sr.js
new file mode 120000
index 0000000..c4fd9d5
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-sr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sv.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sv.js
new file mode 120000
index 0000000..d7f26e0
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-sv.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-sv.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-tr.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-tr.js
new file mode 120000
index 0000000..86fd98f
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-tr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-tr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-uk.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-uk.js
new file mode 120000
index 0000000..7cd1336
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-uk.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-uk.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-zh-CN.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-zh-CN.js
new file mode 120000
index 0000000..e6c5965
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-zh-CN.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-CN.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-zh-TW.js b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-zh-TW.js
new file mode 120000
index 0000000..bd2254c
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/colorbox-i18n/jquery.colorbox-zh-TW.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-TW.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/flowr.plugin.js b/nikola/data/themes/bootstrap-jinja/assets/js/flowr.plugin.js
new file mode 120000
index 0000000..c195756
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/flowr.plugin.js
@@ -0,0 +1 @@
+../../../bootstrap/assets/js/flowr.plugin.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/assets/js/jquery.colorbox.js b/nikola/data/themes/bootstrap-jinja/assets/js/jquery.colorbox.js
new file mode 120000
index 0000000..5ee7a90
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/assets/js/jquery.colorbox.js
@@ -0,0 +1 @@
+../../../../../../bower_components/jquery-colorbox/jquery.colorbox.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/bundles b/nikola/data/themes/bootstrap-jinja/bundles
new file mode 120000
index 0000000..3e517bb
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/bundles
@@ -0,0 +1 @@
+../bootstrap/bundles \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap-jinja/engine b/nikola/data/themes/bootstrap-jinja/engine
new file mode 100644
index 0000000..6f04b30
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/engine
@@ -0,0 +1 @@
+jinja
diff --git a/nikola/data/themes/bootstrap-jinja/parent b/nikola/data/themes/bootstrap-jinja/parent
new file mode 100644
index 0000000..e9ed660
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/parent
@@ -0,0 +1 @@
+base-jinja
diff --git a/nikola/data/themes/bootstrap-jinja/templates/base.tmpl b/nikola/data/themes/bootstrap-jinja/templates/base.tmpl
new file mode 100644
index 0000000..a433721
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/templates/base.tmpl
@@ -0,0 +1,86 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'base_helper.tmpl' as base with context %}
+{% import 'annotation_helper.tmpl' as notes with context %}
+{{ set_locale(lang) }}
+{{ base.html_headstart() }}
+{% block extra_head %}
+{# Leave this block alone. #}
+{% endblock %}
+{{ template_hooks['extra_head']() }}
+</head>
+<body>
+
+<!-- Menubar -->
+
+<div class="navbar navbar-fixed-top" id="navbar">
+ <div class="navbar-inner">
+ <div class="container">
+
+ <!-- .btn-navbar is used as the toggle for collapsed navbar content -->
+ <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </a>
+
+ <a class="brand" href="{{ abs_link('/') }}">
+ {% if logo_url %}
+ <img src="{{ logo_url }}" alt="{{ blog_title }}" id="logo">
+ {% endif %}
+
+ {% if show_blog_title %}
+ <span id="blog-title">{{ blog_title }}</span>
+ {% endif %}
+ </a>
+ <!-- Everything you want hidden at 940px or less, place within here -->
+ <div class="nav-collapse collapse">
+ <ul class="nav">
+ {{ base.html_navigation_links() }}
+ {{ template_hooks['menu']() }}
+ </ul>
+ {% if search_form %}
+ {{ search_form }}
+ {% endif %}
+ <ul class="nav pull-right">
+ {% block belowtitle %}
+ {% if translations|length > 1 %}
+ <li>{{ base.html_translations() }}</li>
+ {% endif %}
+ {% endblock %}
+ {% if show_sourcelink %}
+ <li>{% block sourcelink %}{% endblock %}</li>
+ {% endif %}
+ {{ template_hooks['menu_alt']() }}
+ </ul>
+ </div>
+ </div>
+ </div>
+</div>
+<!-- End of Menubar -->
+<div class="container-fluid" id="container-fluid">
+ <!--Body content-->
+ <div class="row-fluid">
+ <div class="span2"></div>
+ <div class="span8">
+ {{ template_hooks['page_header']() }}
+ {% block content %}{% endblock %}
+ </div>
+ </div>
+ <!--End of body content-->
+</div>
+<div class="footerbox">
+ {{ content_footer }}
+ {{ template_hooks['page_footer']() }}
+</div>
+{{ base.late_load_js() }}
+ <script>jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"100%",maxHeight:"100%",scalePhotos:true});</script>
+ {% block extra_js %}{% endblock %}
+ {% if annotations and post and not post.meta('noannotations') %}
+ {{ notes.code() }}
+ {% elif not annotations and post and post.meta('annotations') %}
+ {{ notes.code() }}
+ {% endif %}
+{{ body_end }}
+{{ template_hooks['body_end']() }}
+</body>
+</html>
diff --git a/nikola/data/themes/bootstrap-jinja/templates/base_helper.tmpl b/nikola/data/themes/bootstrap-jinja/templates/base_helper.tmpl
new file mode 100644
index 0000000..d8398b8
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/templates/base_helper.tmpl
@@ -0,0 +1,161 @@
+{# -*- coding: utf-8 -*- #}
+
+{% macro html_headstart() %}
+<!DOCTYPE html>
+<html
+
+{% if use_open_graph or (twitter_card and twitter_card['use_twitter_cards']) or (comment_system == 'facebook') %}
+prefix='
+{% if use_open_graph or (twitter_card and twitter_card['use_twitter_cards']) %}
+og: http://ogp.me/ns#
+{% endif %}
+{% if use_open_graph %}
+article: http://ogp.me/ns/article#
+{% endif %}
+{% if comment_system == 'facebook' %}
+fb: http://ogp.me/ns/fb#
+{% endif %}
+'
+{% endif %}
+
+{% if is_rtl %}
+dir="rtl"
+{% endif %}
+
+lang="{{ lang }}">
+ <head>
+ <meta charset="utf-8">
+ {% if description %}
+ <meta name="description" content="{{ description }}">
+ {% endif %}
+ <meta name="viewport" content="width=device-width">
+ <title>{{ title|e }} | {{ blog_title|e }}</title>
+
+ {{ html_stylesheets() }}
+ {{ html_feedlinks() }}
+ {% if permalink %}
+ <link rel="canonical" href="{{ abs_link(permalink) }}">
+ {% endif %}
+
+ {% if favicons %}
+ {% for name, file, size in favicons %}
+ <link rel="{{ name }}" href="{{ file }}" sizes="{{ size }}"/>
+ {% endfor %}
+ {% endif %}
+
+ {% if comment_system == 'facebook' %}
+ <meta property="fb:app_id" content="{{ comment_system_id }}">
+ {% endif %}
+
+ {{ mathjax_config }}
+ {% if use_cdn %}
+ <!--[if lt IE 9]><script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
+ {% else %}
+ <!--[if lt IE 9]><script src="/assets/js/html5.js"></script><![endif]-->
+ {% endif %}
+
+ {{ extra_head_data }}
+{% endmacro %}
+
+
+{% macro late_load_js() %}
+ {% if use_bundles %}
+ {% if use_cdn %}
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
+ <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
+ <script src="/assets/js/all.js"></script>
+ {% else %}
+ <script src="/assets/js/all-nocdn.js"></script>
+ {% endif %}
+ {% else %}
+ {% if use_cdn %}
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
+ <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
+ {% else %}
+ <script src="/assets/js/jquery.min.js"></script>
+ <script src="/assets/js/bootstrap.min.js"></script>
+ {% endif %}
+ <script src="/assets/js/jquery.colorbox-min.js"></script>
+ {% endif %}
+ {% if colorbox_locales[lang] %}
+ <script src="/assets/js/colorbox-i18n/jquery.colorbox-{{ colorbox_locales[lang] }}.js"></script>
+ {% endif %}
+ {{ social_buttons_code }}
+{% endmacro %}
+
+
+{% macro html_stylesheets() %}
+ {% if use_bundles %}
+ {% if use_cdn %}
+ <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
+ <link href="/assets/css/all.css" rel="stylesheet" type="text/css">
+ {% else %}
+ <link href="/assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
+ {% endif %}
+ {% else %}
+ {% if use_cdn %}
+ <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
+ {% else %}
+ <link href="/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/bootstrap-responsive.min.css" rel="stylesheet" type="text/css">
+ {% endif %}
+ <link href="/assets/css/rst.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/code.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/colorbox.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/theme.css" rel="stylesheet" type="text/css">
+ {% if has_custom_css %}
+ <link href="/assets/css/custom.css" rel="stylesheet" type="text/css">
+ {% endif %}
+ {% endif %}
+ {% if annotations and post and not post.meta('noannotations') %}
+ {{ notes.css() }}
+ {% elif not annotations and post and post.meta('annotations') %}
+ {{ notes.css() }}
+ {% endif %}
+{% endmacro %}
+
+
+{% macro html_navigation_links() %}
+ {% for url, text in navigation_links[lang] %}
+ {% if url is mapping %}
+ <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ text }}<b class="caret"></b></a>
+ <ul class="dropdown-menu">
+ {% for suburl, text in url %}
+ {% if rel_link(permalink, suburl) == "#" %}
+ <li class="active"><a href="{{ permalink }}">{{ text }}</a>
+ {% else %}
+ <li><a href="{{ suburl }}">{{ text }}</a>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ {% else %}
+ {% if rel_link(permalink, url) == "#" %}
+ <li class="active"><a href="{{ permalink }}">{{ text }}</a>
+ {% else %}
+ <li><a href="{{ url }}">{{ text }}</a>
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+{% endmacro %}
+
+{% macro html_feedlinks() %}
+ {% if rss_link %}
+ {{ rss_link }}
+ {% elif generate_rss %}
+ {% if translations|length > 1 %}
+ {% for language in translations %}
+ <link rel="alternate" type="application/rss+xml" title="RSS ({{ language }})" href="{{ _link('rss', None, language) }}">
+ {% endfor %}
+ {% else %}
+ <link rel="alternate" type="application/rss+xml" title="RSS" href="{{ _link('rss', None) }}">
+ {% endif %}
+ {% endif %}
+{% endmacro %}
+
+{% macro html_translations() %}
+ {% for langname in translations.keys() %}
+ {% if langname != lang %}
+ <li><a href="{{ _link("index", None, langname) }}" rel="alternate" hreflang="{{ langname }}">{{ messages("LANGUAGE", langname) }}</a></li>
+ {% endif %}
+ {% endfor %}
+{% endmacro %}
diff --git a/nikola/data/themes/bootstrap-jinja/templates/bootstrap_helper.tmpl b/nikola/data/themes/bootstrap-jinja/templates/bootstrap_helper.tmpl
new file mode 100644
index 0000000..e426774
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/templates/bootstrap_helper.tmpl
@@ -0,0 +1,78 @@
+{# -*- coding: utf-8 -*- #}
+{# Override only the functions that differ from base_helper.tmpl #}
+
+{% block html_stylesheets %}
+ {% if use_bundles %}
+ {% if use_cdn %}
+ <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
+ <link href="/assets/css/all.css" rel="stylesheet" type="text/css">
+ {% else %}
+ <link href="/assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
+ {% endif %}
+ {% else %}
+ {% if use_cdn %}
+ <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
+ {% else %}
+ <link href="/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/bootstrap-responsive.min.css" rel="stylesheet" type="text/css">
+ {% endif %}
+ <link href="/assets/css/rst.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/code.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/colorbox.css" rel="stylesheet" type="text/css"/>
+ <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"/>
+ {% if has_custom_css %}
+ <link href="/assets/css/custom.css" rel="stylesheet" type="text/css">
+ {% endif %}
+ {% endif %}
+ {% if annotations and post and not post.meta('noannotations') %}
+ {{ notes.css() }}
+ {% elif not annotations and post and post.meta('annotations') %}
+ {{ notes.css() }}
+ {% endif %}
+{% endblock %}
+
+
+{% block late_load_js %}
+ {% if use_bundles %}
+ {% if use_cdn %}
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
+ <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/js/bootstrap.min.js"></script>
+ <script src="/assets/js/all.js"></script>
+ {% else %}
+ <script src="/assets/js/all-nocdn.js"></script>
+ {% endif %}
+ {% else %}
+ {% if use_cdn %}
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
+ <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/js/bootstrap.min.js"></script>
+ {% else %}
+ <script src="/assets/js/jquery-1.11.0.min.js"></script>
+ <script src="/assets/js/bootstrap.min.js"></script>
+ {% endif %}
+ <script src="/assets/js/jquery.colorbox-min.js"></script>
+ {% endif %}
+{% endblock %}
+
+
+{% block html_navigation_links %}
+ {% for url, text in navigation_links[lang] %}
+ {% if url is mapping %}
+ <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ text }}<b class="caret"></b></a>
+ <ul class="dropdown-menu">
+ {% for suburl, text in url %}
+ {% if rel_link(permalink, suburl) == "#" %}
+ <li class="active"><a href="{{ permalink }}">{{ text }}</a>
+ {% else %}
+ <li><a href="{{ suburl }}">{{ text }}</a>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ {% else %}
+ {% if rel_link(permalink, url) == "#" %}
+ <li class="active"><a href="{{ permalink }}">{{ text }}</a>
+ {% else %}
+ <li><a href="{{ url }}">{{ text }}</a>
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+{% endblock %}
diff --git a/nikola/data/themes/bootstrap-jinja/templates/gallery.tmpl b/nikola/data/themes/bootstrap-jinja/templates/gallery.tmpl
new file mode 100644
index 0000000..e3f9f05
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/templates/gallery.tmpl
@@ -0,0 +1,93 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'base.tmpl' %}
+{% import 'comments_helper.tmpl' as comments with context %}
+{% import 'crumbs.tmpl' as ui with context %}
+{% block sourcelink %}{% endblock %}
+
+{% block content %}
+ {{ ui.bar(crumbs) }}
+ {% if title %}
+ <h1>{{ title }}</h1>
+ {% endif %}
+ {% if post %}
+ <p>
+ {{ post.text() }}
+ </p>
+ {% endif %}
+ {% if folders %}
+ <ul>
+ {% for folder, ftitle in folders %}
+ <li><a href="{{ folder }}"><i class="icon-folder-open"></i>&nbsp;{{ ftitle }}</a></li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+
+<div id="gallery_container"></div>
+{% if photo_array %}
+<noscript>
+<ul class="thumbnails">
+ {% for image in photo_array %}
+ <li><a href="{{ image['url'] }}" class="thumbnail image-reference" title="{{ image['title'] }}">
+ <img src="{{ image['url_thumb'] }}" alt="{{ image['title'] }}" /></a>
+ {% endfor %}
+</ul>
+</noscript>
+{% endif %}
+{% if site_has_comments and enable_comments %}
+{{ comments.comment_form(None, permalink, title) }}
+{% endif %}
+{% endblock %}
+
+{% block extra_head %}
+{{ super() }}
+<style type="text/css">
+ .image-block {
+ display: inline-block;
+ }
+ .flowr_row {
+ width: 100%;
+ }
+ </style>
+{% endblock %}
+
+
+{% block extra_js %}
+<script src="/assets/js/flowr.plugin.js"></script>
+<script>
+jsonContent = {{ photo_array_json }};
+$("#gallery_container").flowr({
+ data : jsonContent,
+ height : {{ thumbnail_size }}*.6,
+ padding: 5,
+ rows: -1,
+ render : function(params) {
+ // Just return a div, string or a dom object, anything works fine
+ img = $("<img />").attr({
+ 'src': params.itemData.url_thumb,
+ 'width' : params.width,
+ 'height' : params.height
+ }).css('max-width', '100%');
+ link = $( "<a></a>").attr({
+ 'href': params.itemData.url,
+ 'class': 'image-reference'
+ });
+ div = $("<div />").addClass('image-block').attr({
+ 'title': params.itemData.title,
+ 'data-toggle': "tooltip",
+ });
+ link.append(img);
+ div.append(link);
+ div.hover(div.tooltip());
+ return div;
+ },
+ itemWidth : function(data) { return data.size.w; },
+ itemHeight : function(data) { return data.size.h; },
+ complete : function(params) {
+ if( jsonContent.length > params.renderedItems ) {
+ nextRenderList = jsonContent.slice( params.renderedItems );
+ }
+ }
+ });
+$("a.image-reference").colorbox({rel:"gal", maxWidth:"100%",maxHeight:"100%",scalePhotos:true});
+</script>
+{% endblock %}
diff --git a/nikola/data/themes/bootstrap-jinja/templates/listing.tmpl b/nikola/data/themes/bootstrap-jinja/templates/listing.tmpl
new file mode 100644
index 0000000..4b99f86
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/templates/listing.tmpl
@@ -0,0 +1,28 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'base.tmpl' %}
+{% import 'crumbs.tmpl' as ui with context %}
+
+{% block content %}
+{{ ui.bar(crumbs) }}
+{% if folders or files %}
+<ul class="list-unstyled">
+{% for name in folders %}
+ <li><a href="{{ name }}"><i class="icon-folder-open"></i> {{ name }}</a>
+{% endfor %}
+{% for name in files %}
+ <li><a href="{{ name }}.html"><i class="icon-file"></i> {{ name }}</a>
+{% endfor %}
+</ul>
+{% endif %}
+{% if code %}
+ {{ code }}
+{% endif %}
+{% endblock %}
+
+{% block sourcelink %}
+{% if source_link %}
+ <li>
+ <a href="{{ source_link }}" id="sourcelink">{{ messages("Source") }}</a>
+ </li>
+{% endif %}
+{% endblock %}
diff --git a/nikola/data/themes/bootstrap-jinja/templates/post.tmpl b/nikola/data/themes/bootstrap-jinja/templates/post.tmpl
new file mode 100644
index 0000000..531ebd5
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/templates/post.tmpl
@@ -0,0 +1,47 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'post_helper.tmpl' as helper with context %}
+{% import 'post_header.tmpl' as pheader with context %}
+{% import 'comments_helper.tmpl' as comments with context %}
+{% extends 'base.tmpl' %}
+
+{% block extra_head %}
+ {{ super() }}
+ {% if post.meta('keywords') %}
+ <meta name="keywords" content="{{ post.meta('keywords')|e }}">
+ {% endif %}
+ <meta name="author" content="{{ post.author() }}">
+ {{ helper.open_graph_metadata(post) }}
+ {{ helper.twitter_card_information(post) }}
+ {{ helper.meta_translations(post) }}
+{% endblock %}
+
+{% block content %}
+<article class="post-{{ post.meta('type') }} h-entry hentry postpage" itemscope="itemscope" itemtype="http://schema.org/Article">
+ {{ pheader.html_post_header() }}
+ <div class="e-content entry-content" itemprop="articleBody text">
+ {{ post.text() }}
+ </div>
+ <aside class="postpromonav">
+ <nav>
+ {{ helper.html_tags(post) }}
+ {{ helper.html_pager(post) }}
+ </nav>
+ </aside>
+ {% if not post.meta('nocomments') and site_has_comments %}
+ <section class="comments">
+ <h2>{{ messages("Comments") }}</h2>
+ {{ comments.comment_form(post.permalink(absolute=True), post.title(), post._base_path) }}
+ </section>
+ {% endif %}
+ {{ helper.mathjax_script(post) }}
+</article>
+{{ comments.comment_link_script() }}
+{% endblock %}
+
+{% block sourcelink %}
+{% if show_sourcelink %}
+ <li>
+ <a href="{{ post.source_link() }}" id="sourcelink">{{ messages("Source") }}</a>
+ </li>
+{% endif %}
+{% endblock %}
diff --git a/nikola/data/themes/bootstrap-jinja/templates/post_header.tmpl b/nikola/data/themes/bootstrap-jinja/templates/post_header.tmpl
new file mode 100644
index 0000000..b565244
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/templates/post_header.tmpl
@@ -0,0 +1,40 @@
+{# -*- coding: utf-8 -*- #}
+{% import 'post_helper.tmpl' as helper with context %}
+{% import 'comments_helper.tmpl' as comments with context %}
+
+{% macro html_title() %}
+ <h1 class="p-name entry-title" itemprop="headline name"><a href="{{ post.permalink() }}" class="u-url">{{ title|e }}</a></h1>
+{% endmacro %}
+
+{% macro html_translations(post) %}
+ {% if translations|length > 1 %}
+ <div class="metadata posttranslations translations">
+ <h3 class="posttranslations-intro">{{ messages("Also available in:") }}</h3>
+ {% for langname in translations.keys() %}
+ {% if langname != lang and post.is_translation_available(langname) %}
+ <p><a href="{{ post.permalink(langname) }}" rel="alternate" hreflang="{{ langname }}">{{ messages("LANGUAGE", langname) }}</a></p>
+ {% endif %}
+ {% endfor %}
+ </div>
+ {% endif %}
+{% endmacro %}
+
+{% macro html_post_header() %}
+ <header>
+ {{ html_title() }}
+ <div class="metadata">
+ <p class="byline author vcard"><span class="byline-name fn">{{ post.author() }}</span></p>
+ <p class="dateline"><a href="{{ post.permalink() }}" rel="bookmark"><time class="published dt-published" datetime="{{ post.date.isoformat() }}" itemprop="datePublished" title="{{ messages("Publication date") }}">{{ post.formatted_date(date_format) }}</time></a></p>
+ {% if not post.meta('nocomments') and site_has_comments %}
+ <p class="commentline">{{ comments.comment_link(post.permalink(), post._base_path) }}
+ {% endif %}
+ {% if post.meta('link') %}
+ <p><a href='{{ post.meta('link') }}'>{{ messages("Original site") }}</a></p>
+ {% endif %}
+ {% if post.description() %}
+ <meta content="{{ post.description() }}" itemprop="description">
+ {% endif %}
+ </div>
+ {{ html_translations(post) }}
+ </header>
+{% endmacro %}
diff --git a/nikola/data/themes/bootstrap-jinja/templates/slides.tmpl b/nikola/data/themes/bootstrap-jinja/templates/slides.tmpl
new file mode 100644
index 0000000..0ae8fe8
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/templates/slides.tmpl
@@ -0,0 +1,24 @@
+{% block content %}
+<div id="{{ carousel_id }}" class="carousel slide">
+ <ol class="carousel-indicators">
+ {% for i in range(slides_content|length) %}
+ {% if i == 0 %}
+ <li data-target="#{{ carousel_id }}" data-slide-to="{{ i }}" class="active"></li>
+ {% else %}
+ <li data-target="#{{ carousel_id }}" data-slide-to="{{ i }}"></li>
+ {% endif %}
+ {% endfor %}
+ </ol>
+ <div class="carousel-inner">
+ {% for i, image in enumerate(slides_content) %}
+ {% if i == 0 %}
+ <div class="item active"><img src="{{ image }}" alt="" style="margin: 0 auto 0 auto;"></div>
+ {% else %}
+ <div class="item"><img src="{{ image }}" alt="" style="margin: 0 auto 0 auto;"></div>
+ {% endif %}
+ {% endfor %}
+ </div>
+ <a class="left carousel-control" href="#{{ carousel_id }}" data-slide="prev">&lsaquo;</a>
+ <a class="right carousel-control" href="#{{ carousel_id }}" data-slide="next">&rsaquo;</a>
+</div>
+{% endblock %}
diff --git a/nikola/data/themes/bootstrap-jinja/templates/tags.tmpl b/nikola/data/themes/bootstrap-jinja/templates/tags.tmpl
new file mode 100644
index 0000000..080e621
--- /dev/null
+++ b/nikola/data/themes/bootstrap-jinja/templates/tags.tmpl
@@ -0,0 +1,26 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'base.tmpl' %}
+
+{% block content %}
+<h1>{{ title }}</h1>
+{% if cat_items %}
+ <h2>{{ messages("Categories") }}</h2>
+ <ul class="unstyled">
+ {% for text, link in cat_items %}
+ {% if text %}
+ <li><a class="reference badge" href="{{ link }}">{{ text }}</a></li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ {% if items %}
+ <h2>{{ messages("Tags") }}</h2>
+ {% endif %}
+{% endif %}
+{% if items %}
+ <ul class="list-inline">
+ {% for text, link in items %}
+ <li><a class="reference badge" href="{{ link }}">{{ text }}</a></li>
+ {% endfor %}
+ </ul>
+{% endif %}
+{% endblock %}
diff --git a/nikola/data/themes/bootstrap/assets/css/colorbox.css b/nikola/data/themes/bootstrap/assets/css/colorbox.css
index 13c3308..5f8b3b0 100644..120000
--- a/nikola/data/themes/bootstrap/assets/css/colorbox.css
+++ b/nikola/data/themes/bootstrap/assets/css/colorbox.css
@@ -1,69 +1 @@
-/*
- Colorbox Core Style:
- The following CSS is consistent between example themes and should not be altered.
-*/
-#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
-#cboxOverlay{position:fixed; width:100%; height:100%;}
-#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
-#cboxContent{position:relative;}
-#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;}
-#cboxTitle{margin:0;}
-#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
-#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
-.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;}
-.cboxIframe{width:100%; height:100%; display:block; border:0;}
-#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;}
-
-/*
- User Style:
- Change the following styles to modify the appearance of Colorbox. They are
- ordered & tabbed in a way that represents the nesting of the generated HTML.
-*/
-#cboxOverlay{background:url(images/overlay.png) repeat 0 0;}
-#colorbox{outline:0;}
- #cboxTopLeft{width:21px; height:21px; background:url(images/controls.png) no-repeat -101px 0;}
- #cboxTopRight{width:21px; height:21px; background:url(images/controls.png) no-repeat -130px 0;}
- #cboxBottomLeft{width:21px; height:21px; background:url(images/controls.png) no-repeat -101px -29px;}
- #cboxBottomRight{width:21px; height:21px; background:url(images/controls.png) no-repeat -130px -29px;}
- #cboxMiddleLeft{width:21px; background:url(images/controls.png) left top repeat-y;}
- #cboxMiddleRight{width:21px; background:url(images/controls.png) right top repeat-y;}
- #cboxTopCenter{height:21px; background:url(images/border.png) 0 0 repeat-x;}
- #cboxBottomCenter{height:21px; background:url(images/border.png) 0 -29px repeat-x;}
- #cboxContent{background:#fff; overflow:hidden;}
- .cboxIframe{background:#fff;}
- #cboxError{padding:50px; border:1px solid #ccc;}
- #cboxLoadedContent{margin-bottom:28px;}
- #cboxTitle{position:absolute; bottom:4px; right: 29px; text-align: right; width:100%; color:#949494;}
- #cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;}
- #cboxLoadingOverlay{background:url(images/loading_background.png) no-repeat center center;}
- #cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;}
-
- /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */
- #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; width:auto; background:none; }
-
- /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */
- #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;}
-
- #cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;}
- #cboxPrevious{position:absolute; bottom:0; left:0; background:url(images/controls.png) no-repeat -75px 0; width:25px; height:25px; text-indent:-9999px;}
- #cboxPrevious:hover{background-position:-75px -25px;}
- #cboxNext{position:absolute; bottom:0; left:27px; background:url(images/controls.png) no-repeat -50px 0; width:25px; height:25px; text-indent:-9999px;}
- #cboxNext:hover{background-position:-50px -25px;}
- #cboxClose{position:absolute; bottom:0; right:0; background:url(images/controls.png) no-repeat -25px 0; width:25px; height:25px; text-indent:-9999px;}
- #cboxClose:hover{background-position:-25px -25px;}
-
-/*
- The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill
- when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to or needed in IE9.
- See: http://jacklmoore.com/notes/ie-transparency-problems/
-*/
-.cboxIE #cboxTopLeft,
-.cboxIE #cboxTopCenter,
-.cboxIE #cboxTopRight,
-.cboxIE #cboxBottomLeft,
-.cboxIE #cboxBottomCenter,
-.cboxIE #cboxBottomRight,
-.cboxIE #cboxMiddleLeft,
-.cboxIE #cboxMiddleRight {
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF);
-}
+../../../../../../bower_components/jquery-colorbox/example3/colorbox.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/css/images/controls.png b/nikola/data/themes/bootstrap/assets/css/images/controls.png
index dcfd6fb..841a726 100644..120000
--- a/nikola/data/themes/bootstrap/assets/css/images/controls.png
+++ b/nikola/data/themes/bootstrap/assets/css/images/controls.png
Binary files differ
diff --git a/nikola/data/themes/bootstrap/assets/css/images/loading.gif b/nikola/data/themes/bootstrap/assets/css/images/loading.gif
index b4695d8..b192a75 100644..120000
--- a/nikola/data/themes/bootstrap/assets/css/images/loading.gif
+++ b/nikola/data/themes/bootstrap/assets/css/images/loading.gif
Binary files differ
diff --git a/nikola/data/themes/bootstrap/assets/css/theme.css b/nikola/data/themes/bootstrap/assets/css/theme.css
index 952073f..ccdfda2 100644
--- a/nikola/data/themes/bootstrap/assets/css/theme.css
+++ b/nikola/data/themes/bootstrap/assets/css/theme.css
@@ -101,3 +101,74 @@ h4, h5, h6 {
margin-top: -50px;
padding-top: 60px;
}
+
+.image-block {
+ display: inline-block;
+}
+
+.flowr_row {
+ width: 100%;
+}
+
+.tags {
+ padding-left: 0;
+ margin-left: -5px;
+ list-style: none;
+ text-align: center;
+
+}
+
+.tags > li {
+ display: inline-block;
+ min-width: 10px;
+ padding: 3px 7px;
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ background-color: #999;
+ border-radius: 10px;
+}
+
+.tags > li a {
+ color: #fff;
+}
+
+.metadata p:before,
+.postlist .listdate:before {
+ content: " — ";
+}
+
+.metadata p:first-of-type:before {
+ content: "";
+}
+
+.metadata p {
+ display: inline;
+}
+
+.posttranslations h3 {
+ display: inline;
+ font-size: 1em;
+ font-weight: bold;
+}
+
+.posttranslations h3:last-child {
+ display: none;
+}
+
+.entry-content {
+ margin-top: 1em;
+}
+
+.navbar .brand {
+ padding: 0 20px;
+}
+
+.navbar .brand #blog-title {
+ padding: 10px 0;
+ display: inline-block;
+}
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ar.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ar.js
new file mode 120000
index 0000000..f83073f
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ar.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-ar.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-bg.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-bg.js
new file mode 120000
index 0000000..bafc4e0
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-bg.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-bg.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ca.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ca.js
new file mode 120000
index 0000000..a749232
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ca.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-ca.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-cs.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-cs.js
new file mode 120000
index 0000000..e4a595c
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-cs.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-cs.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-da.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-da.js
new file mode 120000
index 0000000..1e9a1d6
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-da.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-da.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-de.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-de.js
new file mode 120000
index 0000000..748f53b
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-de.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-de.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-es.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-es.js
new file mode 120000
index 0000000..1154fb5
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-es.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-es.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-et.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-et.js
new file mode 120000
index 0000000..483e192
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-et.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-et.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fa.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fa.js
new file mode 120000
index 0000000..a30b13c
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fa.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-fa.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fi.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fi.js
new file mode 120000
index 0000000..2a7e8ad
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fi.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-fi.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fr.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fr.js
new file mode 120000
index 0000000..e359290
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-fr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-fr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-gl.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-gl.js
new file mode 120000
index 0000000..04fa276
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-gl.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-gl.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-gr.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-gr.js
new file mode 120000
index 0000000..d8105ab
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-gr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-gr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-he.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-he.js
new file mode 120000
index 0000000..72dddf5
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-he.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-he.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-hr.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-hr.js
new file mode 120000
index 0000000..34aa3c0
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-hr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-hr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-hu.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-hu.js
new file mode 120000
index 0000000..a87f03c
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-hu.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-hu.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-id.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-id.js
new file mode 120000
index 0000000..31053b8
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-id.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-id.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-it.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-it.js
new file mode 120000
index 0000000..aad9d22
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-it.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-it.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ja.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ja.js
new file mode 120000
index 0000000..3ea27c2
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ja.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-ja.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-kr.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-kr.js
new file mode 120000
index 0000000..3e23b4a
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-kr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-kr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-lt.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-lt.js
new file mode 120000
index 0000000..374b9bb
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-lt.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-lt.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-lv.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-lv.js
new file mode 120000
index 0000000..101b476
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-lv.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-lv.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-my.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-my.js
new file mode 120000
index 0000000..8e14f15
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-my.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-my.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-nl.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-nl.js
new file mode 120000
index 0000000..2d03d48
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-nl.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-nl.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-no.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-no.js
new file mode 120000
index 0000000..9af0ba7
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-no.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-no.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-pl.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-pl.js
new file mode 120000
index 0000000..34f8ab1
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-pl.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-pl.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-pt-br.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-pt-br.js
new file mode 120000
index 0000000..76f289e
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-pt-br.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-pt-br.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ro.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ro.js
new file mode 120000
index 0000000..555f2e6
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ro.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-ro.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ru.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ru.js
new file mode 120000
index 0000000..bac4855
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-ru.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-ru.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-si.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-si.js
new file mode 120000
index 0000000..65b0492
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-si.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-si.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sk.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sk.js
new file mode 120000
index 0000000..99859fd
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sk.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-sk.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sr.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sr.js
new file mode 120000
index 0000000..c4fd9d5
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-sr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sv.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sv.js
new file mode 120000
index 0000000..d7f26e0
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-sv.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-sv.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-tr.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-tr.js
new file mode 120000
index 0000000..86fd98f
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-tr.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-tr.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-uk.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-uk.js
new file mode 120000
index 0000000..7cd1336
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-uk.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-uk.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-zh-CN.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-zh-CN.js
new file mode 120000
index 0000000..e6c5965
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-zh-CN.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-CN.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-zh-TW.js b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-zh-TW.js
new file mode 120000
index 0000000..bd2254c
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/colorbox-i18n/jquery.colorbox-zh-TW.js
@@ -0,0 +1 @@
+../../../../../../../bower_components/jquery-colorbox/i18n/jquery.colorbox-zh-TW.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/assets/js/jquery.colorbox.js b/nikola/data/themes/bootstrap/assets/js/jquery.colorbox.js
new file mode 120000
index 0000000..5ee7a90
--- /dev/null
+++ b/nikola/data/themes/bootstrap/assets/js/jquery.colorbox.js
@@ -0,0 +1 @@
+../../../../../../bower_components/jquery-colorbox/jquery.colorbox.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap/bundles b/nikola/data/themes/bootstrap/bundles
index 14124a3..089b036 100644
--- a/nikola/data/themes/bootstrap/bundles
+++ b/nikola/data/themes/bootstrap/bundles
@@ -1,4 +1,4 @@
assets/css/all-nocdn.css=bootstrap.css,bootstrap-responsive.css,rst.css,code.css,colorbox.css,theme.css,custom.css
assets/css/all.css=rst.css,code.css,colorbox.css,theme.css,custom.css
-assets/js/all-nocdn.js=jquery-1.10.2.min.js,bootstrap.min.js,jquery.colorbox-min.js
+assets/js/all-nocdn.js=jquery.min.js,bootstrap.min.js,jquery.colorbox-min.js
assets/js/all.js=jquery.colorbox-min.js
diff --git a/nikola/data/themes/bootstrap/templates/base.tmpl b/nikola/data/themes/bootstrap/templates/base.tmpl
index 65132b7..a469098 100644
--- a/nikola/data/themes/bootstrap/templates/base.tmpl
+++ b/nikola/data/themes/bootstrap/templates/base.tmpl
@@ -1,28 +1,17 @@
## -*- coding: utf-8 -*-
<%namespace name="base" file="base_helper.tmpl" import="*" />
-<%namespace name="bootstrap" file="bootstrap_helper.tmpl" import="*" />
<%namespace name="notes" file="annotation_helper.tmpl" import="*" />
${set_locale(lang)}
-<!DOCTYPE html>
-<html
-%if comment_system == 'facebook':
-xmlns:fb="http://ogp.me/ns/fb#"
-%endif
-lang="${lang}">
-<head>
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- ${bootstrap.html_head()}
- <%block name="extra_head">
- </%block>
- % if annotations and post and not post.meta('noannotations'):
- ${notes.css()}
- % elif not annotations and post and post.meta('annotations'):
- ${notes.css()}
- % endif
- ${extra_head_data}
+${base.html_headstart()}
+<%block name="extra_head">
+### Leave this block alone.
+</%block>
+${template_hooks['extra_head']()}
</head>
<body>
+
<!-- Menubar -->
+
<div class="navbar navbar-fixed-top" id="navbar">
<div class="navbar-inner">
<div class="container">
@@ -35,12 +24,19 @@ lang="${lang}">
</a>
<a class="brand" href="${abs_link('/')}">
- ${blog_title}
+ %if logo_url:
+ <img src="${logo_url}" alt="${blog_title}" id="logo">
+ %endif
+
+ % if show_blog_title:
+ <span id="blog-title">${blog_title}</span>
+ % endif
</a>
<!-- Everything you want hidden at 940px or less, place within here -->
<div class="nav-collapse collapse">
<ul class="nav">
- ${bootstrap.html_navigation_links()}
+ ${base.html_navigation_links()}
+ ${template_hooks['menu']()}
</ul>
%if search_form:
${search_form}
@@ -51,9 +47,10 @@ lang="${lang}">
<li>${base.html_translations()}</li>
%endif
</%block>
- % if not hide_sourcelink:
+ % if show_sourcelink:
<li><%block name="sourcelink"></%block></li>
%endif
+ ${template_hooks['menu_alt']()}
</ul>
</div>
</div>
@@ -65,6 +62,7 @@ lang="${lang}">
<div class="row-fluid">
<div class="span2"></div>
<div class="span8">
+ ${template_hooks['page_header']()}
<%block name="content"></%block>
</div>
</div>
@@ -72,23 +70,17 @@ lang="${lang}">
</div>
<div class="footerbox">
${content_footer}
+ ${template_hooks['page_footer']()}
</div>
-${bootstrap.late_load_js()}
-${base.html_social()}
- <script type="text/javascript">jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"100%",maxHeight:"100%",scalePhotos:true});
- $(window).on('hashchange', function(){
- if (location.hash && $(location.hash)[0]) {
- $('body').animate({scrollTop: $(location.hash).offset().top - $('#navbar').outerHeight(true)*1.2 }, 1);
- }
- });
- $(document).ready(function(){$(window).trigger('hashchange')});
- </script>
+${base.late_load_js()}
+ <script>jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"100%",maxHeight:"100%",scalePhotos:true});</script>
<%block name="extra_js"></%block>
% if annotations and post and not post.meta('noannotations'):
${notes.code()}
% elif not annotations and post and post.meta('annotations'):
${notes.code()}
% endif
- ${body_end}
+${body_end}
+${template_hooks['body_end']()}
</body>
</html>
diff --git a/nikola/data/themes/bootstrap/templates/bootstrap_helper.tmpl b/nikola/data/themes/bootstrap/templates/base_helper.tmpl
index c041e50..2dcc138 100644
--- a/nikola/data/themes/bootstrap/templates/bootstrap_helper.tmpl
+++ b/nikola/data/themes/bootstrap/templates/base_helper.tmpl
@@ -1,77 +1,117 @@
-## Override only the functions that differ from base_helper.tmpl
-<%def name="html_head()">
+## -*- coding: utf-8 -*-
+
+<%def name="html_headstart()">
+<!DOCTYPE html>
+<html
+\
+% if use_open_graph or (twitter_card and twitter_card['use_twitter_cards']) or (comment_system == 'facebook'):
+prefix='\
+%if use_open_graph or (twitter_card and twitter_card['use_twitter_cards']):
+og: http://ogp.me/ns# \
+%endif
+%if use_open_graph:
+article: http://ogp.me/ns/article# \
+%endif
+%if comment_system == 'facebook':
+fb: http://ogp.me/ns/fb# \
+%endif
+'\
+%endif
+\
+% if is_rtl:
+dir="rtl" \
+% endif
+\
+lang="${lang}">
+ <head>
<meta charset="utf-8">
%if description:
<meta name="description" content="${description}">
%endif
- <meta name="author" content="${blog_author}">
+ <meta name="viewport" content="width=device-width">
<title>${title|striphtml} | ${blog_title|striphtml}</title>
+
+ ${html_stylesheets()}
+ ${html_feedlinks()}
+ %if permalink:
+ <link rel="canonical" href="${abs_link(permalink)}">
+ %endif
+
+ %if favicons:
+ %for name, file, size in favicons:
+ <link rel="${name}" href="${file}" sizes="${size}"/>
+ %endfor
+ %endif
+
+ % if comment_system == 'facebook':
+ <meta property="fb:app_id" content="${comment_system_id}">
+ % endif
+
${mathjax_config}
+ %if use_cdn:
+ <!--[if lt IE 9]><script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
+ %else:
+ <!--[if lt IE 9]><script src="/assets/js/html5.js"></script><![endif]-->
+ %endif
+
+ ${extra_head_data}
+</%def>
+
+
+<%def name="late_load_js()">
%if use_bundles:
%if use_cdn:
- <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
- <link href="/assets/css/all.css" rel="stylesheet" type="text/css">
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
+ <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
+ <script src="/assets/js/all.js"></script>
%else:
- <link href="/assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
+ <script src="/assets/js/all-nocdn.js"></script>
%endif
%else:
%if use_cdn:
- <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
- %else:
- <link href="/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
- <link href="/assets/css/bootstrap-responsive.min.css" rel="stylesheet" type="text/css">
- %endif
- <link href="/assets/css/rst.css" rel="stylesheet" type="text/css">
- <link href="/assets/css/code.css" rel="stylesheet" type="text/css">
- <link href="/assets/css/colorbox.css" rel="stylesheet" type="text/css"/>
- <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"/>
- %if has_custom_css:
- <link href="/assets/css/custom.css" rel="stylesheet" type="text/css">
- %endif
- %endif
- %if permalink:
- <link rel="canonical" href="${abs_link(permalink)}">
- %endif
- <!--[if lt IE 9]>
- <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
- <![endif]-->
- %if rss_link:
- ${rss_link}
- %else:
- %if len(translations) > 1:
- %for language in translations:
- <link rel="alternate" type="application/rss+xml" title="RSS (${language})" href="${_link('rss', None, language)}">
- %endfor
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
+ <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
%else:
- <link rel="alternate" type="application/rss+xml" title="RSS" href="${_link('rss', None)}">
+ <script src="/assets/js/jquery.min.js"></script>
+ <script src="/assets/js/bootstrap.min.js"></script>
%endif
+ <script src="/assets/js/jquery.colorbox-min.js"></script>
%endif
- %if favicons:
- %for name, file, size in favicons:
- <link rel="${name}" href="${file}" sizes="${size}"/>
- %endfor
+ %if colorbox_locales[lang]:
+ <script src="/assets/js/colorbox-i18n/jquery.colorbox-${colorbox_locales[lang]}.js"></script>
%endif
+ ${social_buttons_code}
</%def>
-<%def name="late_load_js()">
+
+<%def name="html_stylesheets()">
%if use_bundles:
%if use_cdn:
- <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" type="text/javascript"></script>
- <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/js/bootstrap.min.js"></script>
- <script src="/assets/js/all.js" type="text/javascript"></script>
+ <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
+ <link href="/assets/css/all.css" rel="stylesheet" type="text/css">
%else:
- <script src="/assets/js/all-nocdn.js" type="text/javascript"></script>
+ <link href="/assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
%endif
%else:
%if use_cdn:
- <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" type="text/javascript"></script>
- <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/js/bootstrap.min.js"></script>
+ <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
%else:
- <script src="/assets/js/jquery-1.10.2.min.js" type="text/javascript"></script>
- <script src="/assets/js/bootstrap.min.js" type="text/javascript"></script>
+ <link href="/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/bootstrap-responsive.min.css" rel="stylesheet" type="text/css">
+ %endif
+ <link href="/assets/css/rst.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/code.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/colorbox.css" rel="stylesheet" type="text/css">
+ <link href="/assets/css/theme.css" rel="stylesheet" type="text/css">
+ %if has_custom_css:
+ <link href="/assets/css/custom.css" rel="stylesheet" type="text/css">
%endif
- <script src="/assets/js/jquery.colorbox-min.js" type="text/javascript"></script>
%endif
+ % if annotations and post and not post.meta('noannotations'):
+ ${notes.css()}
+ % elif not annotations and post and post.meta('annotations'):
+ ${notes.css()}
+ % endif
</%def>
@@ -97,3 +137,25 @@
% endif
%endfor
</%def>
+
+<%def name="html_feedlinks()">
+ %if rss_link:
+ ${rss_link}
+ %elif generate_rss:
+ %if len(translations) > 1:
+ %for language in translations:
+ <link rel="alternate" type="application/rss+xml" title="RSS (${language})" href="${_link('rss', None, language)}">
+ %endfor
+ %else:
+ <link rel="alternate" type="application/rss+xml" title="RSS" href="${_link('rss', None)}">
+ %endif
+ %endif
+</%def>
+
+<%def name="html_translations()">
+ %for langname in translations.keys():
+ %if langname != lang:
+ <li><a href="${_link("index", None, langname)}" rel="alternate" hreflang="${langname}">${messages("LANGUAGE", langname)}</a></li>
+ %endif
+ %endfor
+</%def>
diff --git a/nikola/data/themes/bootstrap/templates/gallery.tmpl b/nikola/data/themes/bootstrap/templates/gallery.tmpl
index 7b0d505..8ad4eb4 100644
--- a/nikola/data/themes/bootstrap/templates/gallery.tmpl
+++ b/nikola/data/themes/bootstrap/templates/gallery.tmpl
@@ -9,38 +9,37 @@
%if title:
<h1>${title}</h1>
%endif
- %if text:
+ %if post:
<p>
- ${text}
+ ${post.text()}
</p>
%endif
%if folders:
<ul>
% for folder, ftitle in folders:
- <li><a href="${folder}"><i
- class="icon-folder-open"></i>&nbsp;${ftitle}</a></li>
+ <li><a href="${folder}"><i class="icon-folder-open"></i>&nbsp;${ftitle}</a></li>
% endfor
</ul>
%endif
- <div id="gallery_container"></div>
- %if photo_array:
- <noscript>
- <ul class="thumbnails">
- %for image in photo_array:
- <li><a href="${image['url']}" class="thumbnail image-reference" title="${image['title']}">
- <img src="${image['url_thumb']}" alt="${image['title']}" /></a>
- %endfor
- </ul>
- </noscript>
- %endif
-%if enable_comments:
- ${comments.comment_form(None, permalink, title)}
+<div id="gallery_container"></div>
+%if photo_array:
+<noscript>
+<ul class="thumbnails">
+ %for image in photo_array:
+ <li><a href="${image['url']}" class="thumbnail image-reference" title="${image['title']}">
+ <img src="${image['url_thumb']}" alt="${image['title']}" /></a>
+ %endfor
+</ul>
+</noscript>
+%endif
+%if site_has_comments and enable_comments:
+${comments.comment_form(None, permalink, title)}
%endif
</%block>
-
<%block name="extra_head">
+${parent.extra_head()}
<style type="text/css">
.image-block {
display: inline-block;
diff --git a/nikola/data/themes/bootstrap/templates/listing.tmpl b/nikola/data/themes/bootstrap/templates/listing.tmpl
new file mode 100644
index 0000000..f03ea23
--- /dev/null
+++ b/nikola/data/themes/bootstrap/templates/listing.tmpl
@@ -0,0 +1,28 @@
+## -*- coding: utf-8 -*-
+<%inherit file="base.tmpl"/>
+<%namespace name="ui" file="crumbs.tmpl" import="bar"/>
+
+<%block name="content">
+${ui.bar(crumbs)}
+%if folders or files:
+<ul class="list-unstyled">
+% for name in folders:
+ <li><a href="${name}"><i class="icon-folder-open"></i> ${name}</a>
+% endfor
+% for name in files:
+ <li><a href="${name}.html"><i class="icon-file"></i> ${name}</a>
+% endfor
+</ul>
+%endif
+% if code:
+ ${code}
+% endif
+</%block>
+
+<%block name="sourcelink">
+% if source_link:
+ <li>
+ <a href="${source_link}" id="sourcelink">${messages("Source")}</a>
+ </li>
+% endif
+</%block>
diff --git a/nikola/data/themes/bootstrap/templates/post.tmpl b/nikola/data/themes/bootstrap/templates/post.tmpl
new file mode 100644
index 0000000..29a5b75
--- /dev/null
+++ b/nikola/data/themes/bootstrap/templates/post.tmpl
@@ -0,0 +1,47 @@
+## -*- coding: utf-8 -*-
+<%namespace name="helper" file="post_helper.tmpl"/>
+<%namespace name="pheader" file="post_header.tmpl"/>
+<%namespace name="comments" file="comments_helper.tmpl"/>
+<%inherit file="base.tmpl"/>
+
+<%block name="extra_head">
+ ${parent.extra_head()}
+ % if post.meta('keywords'):
+ <meta name="keywords" content="${post.meta('keywords')|h}">
+ % endif
+ <meta name="author" content="${post.author()}">
+ ${helper.open_graph_metadata(post)}
+ ${helper.twitter_card_information(post)}
+ ${helper.meta_translations(post)}
+</%block>
+
+<%block name="content">
+<article class="post-${post.meta('type')} h-entry hentry postpage" itemscope="itemscope" itemtype="http://schema.org/Article">
+ ${pheader.html_post_header()}
+ <div class="e-content entry-content" itemprop="articleBody text">
+ ${post.text()}
+ </div>
+ <aside class="postpromonav">
+ <nav>
+ ${helper.html_tags(post)}
+ ${helper.html_pager(post)}
+ </nav>
+ </aside>
+ % if not post.meta('nocomments') and site_has_comments:
+ <section class="comments">
+ <h2>${messages("Comments")}</h2>
+ ${comments.comment_form(post.permalink(absolute=True), post.title(), post._base_path)}
+ </section>
+ % endif
+ ${helper.mathjax_script(post)}
+</article>
+${comments.comment_link_script()}
+</%block>
+
+<%block name="sourcelink">
+% if show_sourcelink:
+ <li>
+ <a href="${post.source_link()}" id="sourcelink">${messages("Source")}</a>
+ </li>
+% endif
+</%block>
diff --git a/nikola/data/themes/bootstrap/templates/slides.tmpl b/nikola/data/themes/bootstrap/templates/slides.tmpl
index 14983ad..048fb7e 100644
--- a/nikola/data/themes/bootstrap/templates/slides.tmpl
+++ b/nikola/data/themes/bootstrap/templates/slides.tmpl
@@ -1,6 +1,7 @@
+<%block name="content">
<div id="${carousel_id}" class="carousel slide">
<ol class="carousel-indicators">
- % for i in range(len(content)):
+ % for i in range(len(slides_content)):
% if i == 0:
<li data-target="#${carousel_id}" data-slide-to="${i}" class="active"></li>
% else:
@@ -9,7 +10,7 @@
% endfor
</ol>
<div class="carousel-inner">
- % for i, image in enumerate(content):
+ % for i, image in enumerate(slides_content):
% if i == 0:
<div class="item active"><img src="${image}" alt="" style="margin: 0 auto 0 auto;"></div>
% else:
@@ -20,3 +21,4 @@
<a class="left carousel-control" href="#${carousel_id}" data-slide="prev">&lsaquo;</a>
<a class="right carousel-control" href="#${carousel_id}" data-slide="next">&rsaquo;</a>
</div>
+</%block>
diff --git a/nikola/data/themes/bootstrap/templates/tags.tmpl b/nikola/data/themes/bootstrap/templates/tags.tmpl
new file mode 100644
index 0000000..9afeca7
--- /dev/null
+++ b/nikola/data/themes/bootstrap/templates/tags.tmpl
@@ -0,0 +1,26 @@
+## -*- coding: utf-8 -*-
+<%inherit file="base.tmpl"/>
+
+<%block name="content">
+<h1>${title}</h1>
+% if cat_items:
+ <h2>${messages("Categories")}</h2>
+ <ul class="unstyled">
+ % for text, link in cat_items:
+ % if text:
+ <li><a class="reference badge" href="${link}">${text}</a></li>
+ % endif
+ % endfor
+ </ul>
+ % if items:
+ <h2>${messages("Tags")}</h2>
+ % endif
+%endif
+% if items:
+ <ul class="list-inline">
+ % for text, link in items:
+ <li><a class="reference badge" href="${link}">${text}</a></li>
+ % endfor
+ </ul>
+% endif
+</%block>
diff --git a/nikola/filters.py b/nikola/filters.py
index aa7ba8a..78d624b 100644
--- a/nikola/filters.py
+++ b/nikola/filters.py
@@ -29,7 +29,7 @@
from .utils import req_missing
from functools import wraps
import os
-import re
+import codecs
import shutil
import subprocess
import tempfile
@@ -41,10 +41,10 @@ except ImportError:
typo = None # NOQA
-def apply_to_file(f):
- """Takes a function f that transforms a data argument, and returns
+def apply_to_binary_file(f):
+ """Take a function f that transforms a data argument, and returns
a function that takes a filename and applies f to the contents,
- in place."""
+ in place. Reads files in binary mode."""
@wraps(f)
def f_in_file(fname):
with open(fname, 'rb') as inf:
@@ -56,15 +56,30 @@ def apply_to_file(f):
return f_in_file
+def apply_to_text_file(f):
+ """Take a function f that transforms a data argument, and returns
+ a function that takes a filename and applies f to the contents,
+ in place. Reads files in UTF-8."""
+ @wraps(f)
+ def f_in_file(fname):
+ with codecs.open(fname, 'r', 'utf-8') as inf:
+ data = inf.read()
+ data = f(data)
+ with codecs.open(fname, 'w+', 'utf-8') as outf:
+ outf.write(data)
+
+ return f_in_file
+
+
def list_replace(the_list, find, replacement):
- "Replaces all occurrences of ``find`` with ``replacement`` in ``the_list``"
+ "Replace all occurrences of ``find`` with ``replacement`` in ``the_list``"
for i, v in enumerate(the_list):
if v == find:
the_list[i] = replacement
def runinplace(command, infile):
- """Runs a command in-place on a file.
+ """Run a command in-place on a file.
command is a string of the form: "commandname %1 %2" and
it will be execed with infile as %1 and a temporary file
@@ -128,60 +143,15 @@ def jpegoptim(infile):
return runinplace(r"jpegoptim -p --strip-all -q %1", infile)
-def tidy(inplace):
- # Google site verifcation files are not HTML
- if re.match(r"google[a-f0-9]+.html", os.path.basename(inplace)) \
- and open(inplace).readline().startswith(
- "google-site-verification:"):
- return
-
- # Tidy will give error exits, that we will ignore.
- output = subprocess.check_output(
- "tidy -m -w 90 --indent no --quote-marks"
- "no --keep-time yes --tidy-mark no "
- "--force-output yes '{0}'; exit 0".format(inplace), stderr=subprocess.STDOUT, shell=True)
-
- for line in output.split("\n"):
- if "Warning:" in line:
- if '<meta> proprietary attribute "charset"' in line:
- # We want to set it though.
- continue
- elif '<meta> lacks "content" attribute' in line:
- # False alarm to me.
- continue
- elif '<div> anchor' in line and 'already defined' in line:
- # Some seeming problem with JavaScript terminators.
- continue
- elif '<img> lacks "alt" attribute' in line:
- # Happens in gallery code, probably can be tolerated.
- continue
- elif '<table> lacks "summary" attribute' in line:
- # Happens for tables, TODO: Check this is normal.
- continue
- elif 'proprietary attribute "data-toggle"' in line or \
- 'proprietary attribute "data-target"':
- # Some of our own tricks
- continue
- else:
- assert False, (inplace, line)
- elif "Error:" in line:
- if '<time> is not recognized' in line:
- # False alarm, time is proper HTML5.
- continue
- else:
- assert False, line
-
-
-@apply_to_file
+@apply_to_text_file
def typogrify(data):
- global typogrify_filter
if typo is None:
- req_missing(['typogrify', 'use the typogrify filter'])
+ req_missing(['typogrify'], 'use the typogrify filter')
data = typo.amp(data)
data = typo.widont(data)
data = typo.smartypants(data)
# Disabled because of typogrify bug where it breaks <title>
- #data = typo.caps(data)
+ # data = typo.caps(data)
data = typo.initial_quotes(data)
return data
diff --git a/nikola/nikola.py b/nikola/nikola.py
index 1d59954..59e1b97 100644
--- a/nikola/nikola.py
+++ b/nikola/nikola.py
@@ -28,6 +28,7 @@ from __future__ import print_function, unicode_literals
import codecs
from collections import defaultdict
from copy import copy
+from pkg_resources import resource_filename
import datetime
import glob
import locale
@@ -43,7 +44,7 @@ try:
import pyphen
except ImportError:
pyphen = None
-import pytz
+import dateutil.tz
import logging
from . import DEBUG
@@ -53,9 +54,18 @@ if DEBUG:
else:
logging.basicConfig(level=logging.ERROR)
+import PyRSS2Gen as rss
+
import lxml.html
from yapsy.PluginManager import PluginManager
+# Default "Read more..." link
+DEFAULT_INDEX_READ_MORE_LINK = '<p class="more"><a href="{link}">{read_more}…</a></p>'
+DEFAULT_RSS_READ_MORE_LINK = '<p><a href="{link}">{read_more}…</a> ({min_remaining_read})</p>'
+
+# Default pattern for translation files' names
+DEFAULT_TRANSLATIONS_PATTERN = '{path}.{lang}.{ext}'
+
from .post import Post
from . import utils
from .plugin_categories import (
@@ -63,20 +73,94 @@ from .plugin_categories import (
LateTask,
PageCompiler,
RestExtension,
+ MarkdownExtension,
Task,
TaskMultiplier,
TemplateSystem,
SignalHandler,
)
-from .utils import ColorfulStderrHandler
config_changed = utils.config_changed
__all__ = ['Nikola']
-# Default pattern for translation files' names
-DEFAULT_TRANSLATIONS_PATTERN = '{path}.{ext}.{lang}'
+# We store legal values for some setting here. For internal use.
+LEGAL_VALUES = {
+ 'COMMENT_SYSTEM': [
+ 'disqus',
+ 'facebook',
+ 'googleplus',
+ 'intensedebate',
+ 'isso',
+ 'livefyre',
+ 'muut',
+ ],
+ 'TRANSLATIONS': {
+ 'bg': 'Bulgarian',
+ 'ca': 'Catalan',
+ ('cs', 'cz'): 'Czech',
+ 'de': 'German',
+ ('el', '!gr'): 'Greek',
+ 'en': 'English',
+ 'eo': 'Esperanto',
+ 'es': 'Spanish',
+ 'et': 'Estonian',
+ 'eu': 'Basque',
+ 'fa': 'Persian',
+ 'fi': 'Finnish',
+ 'fr': 'French',
+ 'hi': 'Hindi',
+ 'hr': 'Croatian',
+ 'it': 'Italian',
+ ('ja', '!jp'): 'Japanese',
+ 'nb': 'Norwegian Bokmål',
+ 'nl': 'Dutch',
+ 'pl': 'Polish',
+ 'pt_br': 'Portuguese (Brasil)',
+ 'ru': 'Russian',
+ 'sk': 'Slovak',
+ 'sl': 'Slovene',
+ ('tr', '!tr_TR'): 'Turkish',
+ 'ur': 'Urdu',
+ 'zh_cn': 'Chinese (Simplified)',
+ },
+ '_TRANSLATIONS_WITH_COUNTRY_SPECIFIERS': {
+ # This dict is used in `init` in case of locales that exist with a
+ # country specifier. If there is no other locale that has the same
+ # language with a different country, ``nikola init`` (but nobody else!)
+ # will accept it, warning the user about it.
+ 'pt': 'pt_br',
+ 'zh': 'zh_cn'
+ },
+ 'RTL_LANGUAGES': ('fa', 'ur'),
+ 'COLORBOX_LOCALES': defaultdict(
+ str,
+ bg='bg',
+ ca='ca',
+ cs='cs',
+ cz='cs',
+ de='de',
+ en='',
+ es='es',
+ et='et',
+ fa='fa',
+ fi='fi',
+ fr='fr',
+ hr='hr',
+ it='it',
+ ja='ja',
+ nb='no',
+ nl='nl',
+ pt_br='pt-br',
+ pl='pl',
+ ru='ru',
+ sk='sk',
+ sl='si', # country code is si, language code is sl, colorbox is wrong
+ tr='tr',
+ zh_cn='zh-CN'
+ )
+}
class Nikola(object):
@@ -85,12 +169,6 @@ class Nikola(object):
Takes a site config as argument on creation.
"""
- EXTRA_PLUGINS = [
- 'planetoid',
- 'ipynb',
- 'local_search',
- 'render_mustache',
- ]
def __init__(self, **config):
"""Setup proper environment for running tasks."""
@@ -117,24 +195,29 @@ class Nikola(object):
self._THEMES = None
self.debug = DEBUG
self.loghandlers = []
- if not config:
- self.configured = False
- self.colorful = False
- else:
- self.configured = True
- self.colorful = config.pop('__colorful__', False)
-
- ColorfulStderrHandler._colorful = self.colorful
+ self.colorful = config.pop('__colorful__', False)
+ self.invariant = config.pop('__invariant__', False)
+ self.quiet = config.pop('__quiet__', False)
+ self.configured = bool(config)
+
+ self.template_hooks = {
+ 'extra_head': utils.TemplateHookRegistry('extra_head', self),
+ 'body_end': utils.TemplateHookRegistry('body_end', self),
+ 'page_header': utils.TemplateHookRegistry('page_header', self),
+ 'menu': utils.TemplateHookRegistry('menu', self),
+ 'menu_alt': utils.TemplateHookRegistry('menu_alt', self),
+ 'page_footer': utils.TemplateHookRegistry('page_footer', self),
+ }
# Maintain API
utils.generic_rss_renderer = self.generic_rss_renderer
# This is the default config
self.config = {
- 'ADD_THIS_BUTTONS': True,
'ANNOTATIONS': False,
'ARCHIVE_PATH': "",
'ARCHIVE_FILENAME': "archive.html",
+ 'BLOG_AUTHOR': 'Default Author',
'BLOG_TITLE': 'Default Title',
'BLOG_DESCRIPTION': 'Default Description',
'BODY_END': "",
@@ -154,16 +237,16 @@ class Nikola(object):
"html": ('.html', '.htm')
},
'CONTENT_FOOTER': '',
+ 'CONTENT_FOOTER_FORMATS': {},
'COPY_SOURCES': True,
'CREATE_MONTHLY_ARCHIVE': False,
'CREATE_SINGLE_ARCHIVE': False,
'DATE_FORMAT': '%Y-%m-%d %H:%M',
'DEFAULT_LANG': "en",
'DEPLOY_COMMANDS': [],
- 'DISABLED_PLUGINS': (),
+ 'DISABLED_PLUGINS': [],
'EXTRA_PLUGINS_DIRS': [],
'COMMENT_SYSTEM_ID': 'nikolademo',
- 'ENABLED_EXTRAS': (),
'EXTRA_HEAD_DATA': '',
'FAVICONS': {},
'FEED_LENGTH': 10,
@@ -171,13 +254,12 @@ class Nikola(object):
'ADDITIONAL_METADATA': {},
'FILES_FOLDERS': {'files': ''},
'FILTERS': {},
+ 'FORCE_ISO8601': False,
'GALLERY_PATH': 'galleries',
'GALLERY_SORT_BY_DATE': True,
'GZIP_COMMAND': None,
'GZIP_FILES': False,
'GZIP_EXTENSIONS': ('.txt', '.htm', '.html', '.css', '.js', '.json', '.xml'),
- 'HIDE_SOURCELINK': False,
- 'HIDE_UNTRANSLATED_POSTS': False,
'HYPHENATE': False,
'INDEX_DISPLAY_POST_COUNT': 10,
'INDEX_FILE': 'index.html',
@@ -192,7 +274,8 @@ class Nikola(object):
'LICENSE': '',
'LINK_CHECK_WHITELIST': [],
'LISTINGS_FOLDER': 'listings',
- 'NAVIGATION_LINKS': None,
+ 'LOGO_URL': '',
+ 'NAVIGATION_LINKS': {},
'MARKDOWN_EXTENSIONS': ['fenced_code', 'codehilite'],
'MAX_IMAGE_SIZE': 1280,
'MATHJAX_CONFIG': '',
@@ -202,14 +285,21 @@ class Nikola(object):
'PAGES': (("stories/*.txt", "stories", "story.tmpl"),),
'PRETTY_URLS': False,
'FUTURE_IS_NOW': False,
- 'READ_MORE_LINK': '<p class="more"><a href="{link}">{read_more}…</a></p>',
+ 'INDEX_READ_MORE_LINK': DEFAULT_INDEX_READ_MORE_LINK,
+ 'RSS_READ_MORE_LINK': DEFAULT_RSS_READ_MORE_LINK,
'REDIRECTIONS': [],
+ 'ROBOTS_EXCLUSIONS': [],
+ 'GENERATE_RSS': True,
'RSS_LINK': None,
'RSS_PATH': '',
+ 'RSS_PLAIN': False,
'RSS_TEASERS': True,
'SASS_COMPILER': 'sass',
'SASS_OPTIONS': [],
'SEARCH_FORM': '',
+ 'SHOW_BLOG_TITLE': True,
+ 'SHOW_SOURCELINK': True,
+ 'SHOW_UNTRANSLATED_POSTS': True,
'SLUG_TAG_PATH': True,
'SOCIAL_BUTTONS_CODE': SOCIAL_BUTTONS_CODE,
'SITE_URL': 'http://getnikola.com/',
@@ -223,23 +313,82 @@ class Nikola(object):
'THEME_REVEAL_CONFIG_SUBTHEME': 'sky',
'THEME_REVEAL_CONFIG_TRANSITION': 'cube',
'THUMBNAIL_SIZE': 180,
+ 'UNSLUGIFY_TITLES': False, # WARNING: conf.py.in overrides this with True for backwards compatibility
'URL_TYPE': 'rel_path',
'USE_BUNDLES': True,
'USE_CDN': False,
'USE_FILENAME_AS_TITLE': True,
+ 'USE_OPEN_GRAPH': True,
'TIMEZONE': 'UTC',
'DEPLOY_DRAFTS': True,
'DEPLOY_FUTURE': False,
'SCHEDULE_ALL': False,
'SCHEDULE_RULE': '',
- 'SCHEDULE_FORCE_TODAY': False,
'LOGGING_HANDLERS': {'stderr': {'loglevel': 'WARNING', 'bubble': True}},
'DEMOTE_HEADERS': 1,
- 'TRANSLATIONS_PATTERN': DEFAULT_TRANSLATIONS_PATTERN,
}
+ # set global_context for template rendering
+ self._GLOBAL_CONTEXT = {}
+
self.config.update(config)
+ # __builtins__ contains useless cruft
+ if '__builtins__' in self.config:
+ try:
+ del self.config['__builtins__']
+ except KeyError:
+ del self.config[b'__builtins__']
+
+ self.config['__colorful__'] = self.colorful
+ self.config['__invariant__'] = self.invariant
+ self.config['__quiet__'] = self.quiet
+
+ # Make sure we have sane NAVIGATION_LINKS.
+ if not self.config['NAVIGATION_LINKS']:
+ self.config['NAVIGATION_LINKS'] = {self.config['DEFAULT_LANG']: ()}
+
+ # Translatability configuration.
+ self.config['TRANSLATIONS'] = self.config.get('TRANSLATIONS',
+ {self.config['DEFAULT_LANG']: ''})
+ utils.TranslatableSetting.default_lang = self.config['DEFAULT_LANG']
+
+ self.TRANSLATABLE_SETTINGS = ('BLOG_AUTHOR',
+ 'BLOG_TITLE',
+ 'BLOG_DESCRIPTION',
+ 'LICENSE',
+ 'CONTENT_FOOTER',
+ 'SOCIAL_BUTTONS_CODE',
+ 'SEARCH_FORM',
+ 'BODY_END',
+ 'EXTRA_HEAD_DATA',
+ 'NAVIGATION_LINKS',
+ 'INDEX_READ_MORE_LINK',
+ 'RSS_READ_MORE_LINK',)
+
+ self._GLOBAL_CONTEXT_TRANSLATABLE = ('blog_author',
+ 'blog_title',
+ 'blog_desc', # TODO: remove in v8
+ 'blog_description',
+ 'license',
+ 'content_footer',
+ 'social_buttons_code',
+ 'search_form',
+ 'body_end',
+ 'extra_head_data',)
+ # WARNING: navigation_links SHOULD NOT be added to the list above.
+ # Themes ask for [lang] there and we should provide it.
+
+ for i in self.TRANSLATABLE_SETTINGS:
+ try:
+ self.config[i] = utils.TranslatableSetting(i, self.config[i], self.config['TRANSLATIONS'])
+ except KeyError:
+ pass
+
+ # Handle CONTENT_FOOTER properly.
+ # We provide the arguments to format in CONTENT_FOOTER_FORMATS.
+ self.config['CONTENT_FOOTER'].langformat(self.config['CONTENT_FOOTER_FORMATS'])
+
# Make sure we have pyphen installed if we are using it
if self.config.get('HYPHENATE') and pyphen is None:
utils.LOGGER.warn('To use the hyphenation, you have to install '
@@ -247,24 +396,6 @@ class Nikola(object):
utils.LOGGER.warn('Setting HYPHENATE to False.')
self.config['HYPHENATE'] = False
- # Deprecating post_compilers
- # TODO: remove on v7
- if 'post_compilers' in config:
- utils.LOGGER.warn('The post_compilers option is deprecated, use COMPILERS instead.')
- if 'COMPILERS' in config:
- utils.LOGGER.warn('COMPILERS conflicts with post_compilers, ignoring post_compilers.')
- else:
- self.config['COMPILERS'] = config['post_compilers']
-
- # Deprecating post_pages
- # TODO: remove on v7
- if 'post_pages' in config:
- utils.LOGGER.warn('The post_pages option is deprecated, use POSTS and PAGES instead.')
- if 'POSTS' in config or 'PAGES' in config:
- utils.LOGGER.warn('POSTS and PAGES conflict with post_pages, ignoring post_pages.')
- else:
- self.config['POSTS'] = [item[:3] for item in config['post_pages'] if item[-1]]
- self.config['PAGES'] = [item[:3] for item in config['post_pages'] if not item[-1]]
# FIXME: Internally, we still use post_pages because it's a pain to change it
self.config['post_pages'] = []
for i1, i2, i3 in self.config['POSTS']:
@@ -272,80 +403,78 @@ class Nikola(object):
for i1, i2, i3 in self.config['PAGES']:
self.config['post_pages'].append([i1, i2, i3, False])
- # Deprecating DISQUS_FORUM
- # TODO: remove on v7
- if 'DISQUS_FORUM' in config:
- utils.LOGGER.warn('The DISQUS_FORUM option is deprecated, use COMMENT_SYSTEM_ID instead.')
- if 'COMMENT_SYSTEM_ID' in config:
- utils.LOGGER.warn('DISQUS_FORUM conflicts with COMMENT_SYSTEM_ID, ignoring DISQUS_FORUM.')
+ # DEFAULT_TRANSLATIONS_PATTERN was changed from "p.e.l" to "p.l.e"
+ # TODO: remove on v8
+ if 'TRANSLATIONS_PATTERN' not in self.config:
+ if len(self.config.get('TRANSLATIONS', {})) > 1:
+ utils.LOGGER.warn('You do not have a TRANSLATIONS_PATTERN set in your config, yet you have multiple languages.')
+ utils.LOGGER.warn('Setting TRANSLATIONS_PATTERN to the pre-v6 default ("{path}.{ext}.{lang}").')
+ utils.LOGGER.warn('Please add the proper pattern to your conf.py. (The new default in v7 is "{0}".)'.format(DEFAULT_TRANSLATIONS_PATTERN))
+ self.config['TRANSLATIONS_PATTERN'] = "{path}.{ext}.{lang}"
else:
- self.config['COMMENT_SYSTEM_ID'] = config['DISQUS_FORUM']
-
- # Deprecating the ANALYTICS option
- # TODO: remove on v7
- if 'ANALYTICS' in config:
- utils.LOGGER.warn('The ANALYTICS option is deprecated, use BODY_END instead.')
- if 'BODY_END' in config:
- utils.LOGGER.warn('ANALYTICS conflicts with BODY_END, ignoring ANALYTICS.')
+ # use v7 default there
+ self.config['TRANSLATIONS_PATTERN'] = DEFAULT_TRANSLATIONS_PATTERN
+
+ # HIDE_SOURCELINK has been replaced with the inverted SHOW_SOURCELINK
+ # TODO: remove on v8
+ if 'HIDE_SOURCELINK' in config:
+ utils.LOGGER.warn('The HIDE_SOURCELINK option is deprecated, use SHOW_SOURCELINK instead.')
+ if 'SHOW_SOURCELINK' in config:
+ utils.LOGGER.warn('HIDE_SOURCELINK conflicts with SHOW_SOURCELINK, ignoring HIDE_SOURCELINK.')
+ self.config['SHOW_SOURCELINK'] = not config['HIDE_SOURCELINK']
+
+ # HIDE_UNTRANSLATED_POSTS has been replaced with the inverted SHOW_UNTRANSLATED_POSTS
+ # TODO: remove on v8
+ if 'HIDE_UNTRANSLATED_POSTS' in config:
+ utils.LOGGER.warn('The HIDE_UNTRANSLATED_POSTS option is deprecated, use SHOW_UNTRANSLATED_POSTS instead.')
+ if 'SHOW_UNTRANSLATED_POSTS' in config:
+ utils.LOGGER.warn('HIDE_UNTRANSLATED_POSTS conflicts with SHOW_UNTRANSLATED_POSTS, ignoring HIDE_UNTRANSLATED_POSTS.')
+ self.config['SHOW_UNTRANSLATED_POSTS'] = not config['HIDE_UNTRANSLATED_POSTS']
+
+ # READ_MORE_LINK has been split into INDEX_READ_MORE_LINK and RSS_READ_MORE_LINK
+ # TODO: remove on v8
+ if 'READ_MORE_LINK' in config:
+ utils.LOGGER.warn('The READ_MORE_LINK option is deprecated, use INDEX_READ_MORE_LINK and RSS_READ_MORE_LINK instead.')
+ if 'INDEX_READ_MORE_LINK' in config:
+ utils.LOGGER.warn('READ_MORE_LINK conflicts with INDEX_READ_MORE_LINK, ignoring READ_MORE_LINK.')
else:
- self.config['BODY_END'] = config['ANALYTICS']
-
- # Deprecating the SIDEBAR_LINKS option
- # TODO: remove on v7
- if 'SIDEBAR_LINKS' in config:
- utils.LOGGER.warn('The SIDEBAR_LINKS option is deprecated, use NAVIGATION_LINKS instead.')
- if 'NAVIGATION_LINKS' in config:
- utils.LOGGER.warn('The SIDEBAR_LINKS conflicts with NAVIGATION_LINKS, ignoring SIDEBAR_LINKS.')
+ self.config['INDEX_READ_MORE_LINK'] = utils.TranslatableSetting('INDEX_READ_MORE_LINK', config['READ_MORE_LINK'], self.config['TRANSLATIONS'])
+
+ if 'RSS_READ_MORE_LINK' in config:
+ utils.LOGGER.warn('READ_MORE_LINK conflicts with RSS_READ_MORE_LINK, ignoring READ_MORE_LINK.')
else:
- self.config['NAVIGATION_LINKS'] = config['SIDEBAR_LINKS']
- # Compatibility alias
- self.config['SIDEBAR_LINKS'] = self.config['NAVIGATION_LINKS']
+ self.config['RSS_READ_MORE_LINK'] = utils.TranslatableSetting('RSS_READ_MORE_LINK', config['READ_MORE_LINK'], self.config['TRANSLATIONS'])
- if self.config['NAVIGATION_LINKS'] in (None, {}):
- self.config['NAVIGATION_LINKS'] = {self.config['DEFAULT_LANG']: ()}
+ # Moot.it renamed themselves to muut.io
+ # TODO: remove on v8?
+ if self.config.get('COMMENT_SYSTEM') == 'moot':
+ utils.LOGGER.warn('The moot comment system has been renamed to muut by the upstream. Setting COMMENT_SYSTEM to "muut".')
+ self.config['COMMENT_SYSTEM'] = 'muut'
+
+ # Disable RSS. For a successful disable, we must have both the option
+ # false and the plugin disabled through the official means.
+ if 'generate_rss' in self.config['DISABLED_PLUGINS'] and self.config['GENERATE_RSS'] is True:
+ self.config['GENERATE_RSS'] = False
- # Deprecating the ADD_THIS_BUTTONS option
- # TODO: remove on v7
- if 'ADD_THIS_BUTTONS' in config:
- utils.LOGGER.warn('The ADD_THIS_BUTTONS option is deprecated, use SOCIAL_BUTTONS_CODE instead.')
- if not config['ADD_THIS_BUTTONS']:
- utils.LOGGER.warn('Setting SOCIAL_BUTTONS_CODE to empty because ADD_THIS_BUTTONS is False.')
- self.config['SOCIAL_BUTTONS_CODE'] = ''
-
- # STRIP_INDEX_HTML config has been replaces with STRIP_INDEXES
- # Port it if only the oldef form is there
- # TODO: remove on v7
- if 'STRIP_INDEX_HTML' in config and 'STRIP_INDEXES' not in config:
- utils.LOGGER.warn('You should configure STRIP_INDEXES instead of STRIP_INDEX_HTML')
- self.config['STRIP_INDEXES'] = config['STRIP_INDEX_HTML']
+ if not self.config['GENERATE_RSS'] and 'generate_rss' not in self.config['DISABLED_PLUGINS']:
+ self.config['DISABLED_PLUGINS'].append('generate_rss')
# PRETTY_URLS defaults to enabling STRIP_INDEXES unless explicitly disabled
if self.config.get('PRETTY_URLS') and 'STRIP_INDEXES' not in config:
self.config['STRIP_INDEXES'] = True
if not self.config.get('COPY_SOURCES'):
- self.config['HIDE_SOURCELINK'] = True
-
- self.config['TRANSLATIONS'] = self.config.get('TRANSLATIONS',
- {self.config['DEFAULT_LANG']: ''})
-
- # SITE_URL is required, but if the deprecated BLOG_URL
- # is available, use it and warn
- # TODO: remove on v7
- if 'SITE_URL' not in self.config:
- if 'BLOG_URL' in self.config:
- utils.LOGGER.warn('You should configure SITE_URL instead of BLOG_URL')
- self.config['SITE_URL'] = self.config['BLOG_URL']
+ self.config['SHOW_SOURCELINK'] = False
self.default_lang = self.config['DEFAULT_LANG']
self.translations = self.config['TRANSLATIONS']
- locale_fallback, locale_default, locales = sanitized_locales(
- self.config.get('LOCALE_FALLBACK', None),
- self.config.get('LOCALE_DEFAULT', None),
- self.config.get('LOCALES', {}),
- self.translations) # NOQA
- utils.LocaleBorg.initialize(locales, self.default_lang)
+ if self.configured:
+ locale_fallback, locale_default, locales = sanitized_locales(
+ self.config.get('LOCALE_FALLBACK', None),
+ self.config.get('LOCALE_DEFAULT', None),
+ self.config.get('LOCALES', {}), self.translations)
+ utils.LocaleBorg.initialize(locales, self.default_lang)
# BASE_URL defaults to SITE_URL
if 'BASE_URL' not in self.config:
@@ -354,6 +483,10 @@ class Nikola(object):
if self.config['BASE_URL'] and self.config['BASE_URL'][-1] != '/':
utils.LOGGER.warn("Your BASE_URL doesn't end in / -- adding it.")
+ # We use one global tzinfo object all over Nikola.
+ self.tzinfo = dateutil.tz.gettz(self.config['TIMEZONE'])
+ self.config['__tzinfo__'] = self.tzinfo
+
self.plugin_manager = PluginManager(categories_filter={
"Command": Command,
"Task": Task,
@@ -362,19 +495,22 @@ class Nikola(object):
"PageCompiler": PageCompiler,
"TaskMultiplier": TaskMultiplier,
"RestExtension": RestExtension,
+ "MarkdownExtension": MarkdownExtension,
"SignalHandler": SignalHandler,
})
self.plugin_manager.setPluginInfoExtension('plugin')
extra_plugins_dirs = self.config['EXTRA_PLUGINS_DIRS']
if sys.version_info[0] == 3:
places = [
- os.path.join(os.path.dirname(__file__), 'plugins'),
+ resource_filename('nikola', 'plugins'),
os.path.join(os.getcwd(), 'plugins'),
+ os.path.expanduser('~/.nikola/plugins'),
] + [path for path in extra_plugins_dirs if path]
else:
places = [
- os.path.join(os.path.dirname(__file__), utils.sys_encode('plugins')),
+ resource_filename('nikola', utils.sys_encode('plugins')),
os.path.join(os.getcwd(), utils.sys_encode('plugins')),
+ os.path.expanduser('~/.nikola/plugins'),
] + [utils.sys_encode(path) for path in extra_plugins_dirs if path]
self.plugin_manager.setPluginPlaces(places)
@@ -391,26 +527,22 @@ class Nikola(object):
# Emit signal for SignalHandlers which need to start running immediately.
signal('sighandlers_loaded').send(self)
- self.commands = {}
+ self._commands = {}
# Activate all command plugins
for plugin_info in self.plugin_manager.getPluginsOfCategory("Command"):
- if (plugin_info.name in self.config['DISABLED_PLUGINS']
- or (plugin_info.name in self.EXTRA_PLUGINS and
- plugin_info.name not in self.config['ENABLED_EXTRAS'])):
+ if plugin_info.name in self.config['DISABLED_PLUGINS']:
self.plugin_manager.removePluginFromCategory(plugin_info, "Command")
continue
self.plugin_manager.activatePluginByName(plugin_info.name)
plugin_info.plugin_object.set_site(self)
plugin_info.plugin_object.short_help = plugin_info.description
- self.commands[plugin_info.name] = plugin_info.plugin_object
+ self._commands[plugin_info.name] = plugin_info.plugin_object
# Activate all task plugins
for task_type in ["Task", "LateTask"]:
for plugin_info in self.plugin_manager.getPluginsOfCategory(task_type):
- if (plugin_info.name in self.config['DISABLED_PLUGINS']
- or (plugin_info.name in self.EXTRA_PLUGINS and
- plugin_info.name not in self.config['ENABLED_EXTRAS'])):
+ if plugin_info.name in self.config['DISABLED_PLUGINS']:
self.plugin_manager.removePluginFromCategory(plugin_info, task_type)
continue
self.plugin_manager.activatePluginByName(plugin_info.name)
@@ -418,20 +550,24 @@ class Nikola(object):
# Activate all multiplier plugins
for plugin_info in self.plugin_manager.getPluginsOfCategory("TaskMultiplier"):
- if (plugin_info.name in self.config['DISABLED_PLUGINS']
- or (plugin_info.name in self.EXTRA_PLUGINS and
- plugin_info.name not in self.config['ENABLED_EXTRAS'])):
+ if plugin_info.name in self.config['DISABLED_PLUGINS']:
self.plugin_manager.removePluginFromCategory(plugin_info, task_type)
continue
self.plugin_manager.activatePluginByName(plugin_info.name)
plugin_info.plugin_object.set_site(self)
+ compilers = defaultdict(set)
# Also add aliases for combinations with TRANSLATIONS_PATTERN
- self.config['COMPILERS'] = dict([(lang, list(exts) + [
- utils.get_translation_candidate(self.config, "f" + ext, lang)[1:]
- for ext in exts
- for lang in self.config['TRANSLATIONS'].keys()])
- for lang, exts in list(self.config['COMPILERS'].items())])
+ for compiler, exts in self.config['COMPILERS'].items():
+ for ext in exts:
+ compilers[compiler].add(ext)
+ for lang in self.config['TRANSLATIONS'].keys():
+ candidate = utils.get_translation_candidate(self.config, "f" + ext, lang)
+ compilers[compiler].add(candidate)
+
+ # Avoid redundant compilers
+ for k, v in compilers.items():
+ self.config['COMPILERS'][k] = sorted(list(v))
# Activate all required compiler plugins
for plugin_info in self.plugin_manager.getPluginsOfCategory("PageCompiler"):
@@ -439,11 +575,13 @@ class Nikola(object):
self.plugin_manager.activatePluginByName(plugin_info.name)
plugin_info.plugin_object.set_site(self)
- # set global_context for template rendering
- self._GLOBAL_CONTEXT = {}
-
+ self._GLOBAL_CONTEXT['url_type'] = self.config['URL_TYPE']
+ self._GLOBAL_CONTEXT['timezone'] = self.tzinfo
self._GLOBAL_CONTEXT['_link'] = self.link
- self._GLOBAL_CONTEXT['set_locale'] = utils.LocaleBorg().set_locale
+ try:
+ self._GLOBAL_CONTEXT['set_locale'] = utils.LocaleBorg().set_locale
+ except utils.LocaleBorgUninitializedException:
+ self._GLOBAL_CONTEXT['set_locale'] = None
self._GLOBAL_CONTEXT['rel_link'] = self.rel_link
self._GLOBAL_CONTEXT['abs_link'] = self.abs_link
self._GLOBAL_CONTEXT['exists'] = self.file_exists
@@ -458,49 +596,45 @@ class Nikola(object):
'DATE_FORMAT', '%Y-%m-%d %H:%M')
self._GLOBAL_CONTEXT['blog_author'] = self.config.get('BLOG_AUTHOR')
self._GLOBAL_CONTEXT['blog_title'] = self.config.get('BLOG_TITLE')
+ self._GLOBAL_CONTEXT['show_blog_title'] = self.config.get('SHOW_BLOG_TITLE')
+ self._GLOBAL_CONTEXT['logo_url'] = self.config.get('LOGO_URL')
+ self._GLOBAL_CONTEXT['blog_description'] = self.config.get('BLOG_DESCRIPTION')
- # TODO: remove fallback in v7
- self._GLOBAL_CONTEXT['blog_url'] = self.config.get('SITE_URL', self.config.get('BLOG_URL'))
+ # TODO: remove in v8
self._GLOBAL_CONTEXT['blog_desc'] = self.config.get('BLOG_DESCRIPTION')
+
+ self._GLOBAL_CONTEXT['blog_url'] = self.config.get('SITE_URL')
+ self._GLOBAL_CONTEXT['template_hooks'] = self.template_hooks
self._GLOBAL_CONTEXT['body_end'] = self.config.get('BODY_END')
- # TODO: remove in v7
- self._GLOBAL_CONTEXT['analytics'] = self.config.get('BODY_END')
- # TODO: remove in v7
- self._GLOBAL_CONTEXT['add_this_buttons'] = self.config.get('SOCIAL_BUTTONS_CODE')
self._GLOBAL_CONTEXT['social_buttons_code'] = self.config.get('SOCIAL_BUTTONS_CODE')
self._GLOBAL_CONTEXT['translations'] = self.config.get('TRANSLATIONS')
self._GLOBAL_CONTEXT['license'] = self.config.get('LICENSE')
self._GLOBAL_CONTEXT['search_form'] = self.config.get('SEARCH_FORM')
self._GLOBAL_CONTEXT['comment_system'] = self.config.get('COMMENT_SYSTEM')
self._GLOBAL_CONTEXT['comment_system_id'] = self.config.get('COMMENT_SYSTEM_ID')
- # TODO: remove in v7
- self._GLOBAL_CONTEXT['disqus_forum'] = self.config.get('COMMENT_SYSTEM_ID')
+ self._GLOBAL_CONTEXT['site_has_comments'] = bool(self.config.get('COMMENT_SYSTEM'))
self._GLOBAL_CONTEXT['mathjax_config'] = self.config.get(
'MATHJAX_CONFIG')
self._GLOBAL_CONTEXT['subtheme'] = self.config.get('THEME_REVEAL_CONFIG_SUBTHEME')
self._GLOBAL_CONTEXT['transition'] = self.config.get('THEME_REVEAL_CONFIG_TRANSITION')
self._GLOBAL_CONTEXT['content_footer'] = self.config.get(
'CONTENT_FOOTER')
+ self._GLOBAL_CONTEXT['generate_rss'] = self.config.get('GENERATE_RSS')
self._GLOBAL_CONTEXT['rss_path'] = self.config.get('RSS_PATH')
self._GLOBAL_CONTEXT['rss_link'] = self.config.get('RSS_LINK')
- self._GLOBAL_CONTEXT['navigation_links'] = utils.Functionary(list, self.config['DEFAULT_LANG'])
- for k, v in self.config.get('NAVIGATION_LINKS', {}).items():
- self._GLOBAL_CONTEXT['navigation_links'][k] = v
-
- # avoid #1082 by making sure all keys in navigation_links are read once
- for k in self._GLOBAL_CONTEXT['translations']:
- self._GLOBAL_CONTEXT['navigation_links'][k]
-
- # TODO: remove on v7
- # Compatibility alias
- self._GLOBAL_CONTEXT['sidebar_links'] = self._GLOBAL_CONTEXT['navigation_links']
+ self._GLOBAL_CONTEXT['navigation_links'] = self.config.get('NAVIGATION_LINKS')
+ self._GLOBAL_CONTEXT['use_open_graph'] = self.config.get(
+ 'USE_OPEN_GRAPH', True)
self._GLOBAL_CONTEXT['twitter_card'] = self.config.get(
'TWITTER_CARD', {})
- self._GLOBAL_CONTEXT['hide_sourcelink'] = self.config.get(
- 'HIDE_SOURCELINK')
+ self._GLOBAL_CONTEXT['hide_sourcelink'] = not self.config.get(
+ 'SHOW_SOURCELINK')
+ self._GLOBAL_CONTEXT['show_sourcelink'] = self.config.get(
+ 'SHOW_SOURCELINK')
self._GLOBAL_CONTEXT['extra_head_data'] = self.config.get('EXTRA_HEAD_DATA')
+ self._GLOBAL_CONTEXT['colorbox_locales'] = LEGAL_VALUES['COLORBOX_LOCALES']
self._GLOBAL_CONTEXT.update(self.config.get('GLOBAL_CONTEXT', {}))
@@ -512,29 +646,15 @@ class Nikola(object):
"PageCompiler"):
self.compilers[plugin_info.name] = \
plugin_info.plugin_object
+
signal('configured').send(self)
def _get_themes(self):
if self._THEMES is None:
- # Check for old theme names (Issue #650) TODO: remove in v7
- theme_replacements = {
- 'site': 'bootstrap',
- 'orphan': 'base',
- 'default': 'oldfashioned',
- }
- if self.config['THEME'] in theme_replacements:
- utils.LOGGER.warn('You are using the old theme "{0}", using "{1}" instead.'.format(
- self.config['THEME'], theme_replacements[self.config['THEME']]))
- self.config['THEME'] = theme_replacements[self.config['THEME']]
- if self.config['THEME'] == 'oldfashioned':
- utils.LOGGER.warn('''You may need to install the "oldfashioned" theme '''
- '''from themes.getnikola.com because it's not '''
- '''shipped by default anymore.''')
- utils.LOGGER.warn('Please change your THEME setting.')
try:
self._THEMES = utils.get_theme_chain(self.config['THEME'])
except Exception:
- utils.LOGGER.warn('''Can't load theme "{0}", using 'bootstrap' instead.'''.format(self.config['THEME']))
+ utils.LOGGER.warn('''Cannot load theme "{0}", using 'bootstrap' instead.'''.format(self.config['THEME']))
self.config['THEME'] = 'bootstrap'
return self._get_themes()
# Check consistency of USE_CDN and the current THEME (Issue #386)
@@ -549,9 +669,13 @@ class Nikola(object):
THEMES = property(_get_themes)
def _get_messages(self):
- return utils.load_messages(self.THEMES,
- self.translations,
- self.default_lang)
+ try:
+ return utils.load_messages(self.THEMES,
+ self.translations,
+ self.default_lang)
+ except utils.LanguageNotFoundError as e:
+ utils.LOGGER.error('''Cannot load language "{0}". Please make sure it is supported by Nikola itself, or that you have the appropriate messages files in your themes.'''.format(e.lang))
+ sys.exit(1)
MESSAGES = property(_get_messages)
@@ -633,8 +757,14 @@ class Nikola(object):
local_context["template_name"] = template_name
local_context.update(self.GLOBAL_CONTEXT)
local_context.update(context)
+ for k in self._GLOBAL_CONTEXT_TRANSLATABLE:
+ local_context[k] = local_context[k](local_context['lang'])
+ local_context['is_rtl'] = local_context['lang'] in LEGAL_VALUES['RTL_LANGUAGES']
# string, arguments
local_context["formatmsg"] = lambda s, *a: s % a
+ for h in local_context['template_hooks'].values():
+ h.context = context
+
data = self.template_system.render_template(
template_name, None, local_context)
@@ -652,7 +782,7 @@ class Nikola(object):
utils.makedirs(os.path.dirname(output_name))
doc = lxml.html.document_fromstring(data)
doc.rewrite_links(lambda dst: self.url_replacer(src, dst, context['lang']))
- data = b'<!DOCTYPE html>' + lxml.html.tostring(doc, encoding='utf8')
+ data = b'<!DOCTYPE html>\n' + lxml.html.tostring(doc, encoding='utf8', method='html', pretty_print=True)
with open(output_name, "wb+") as post_file:
post_file.write(data)
@@ -745,30 +875,44 @@ class Nikola(object):
return result
def generic_rss_renderer(self, lang, title, link, description, timeline, output_path,
- rss_teasers, feed_length=10, feed_url=None):
+ rss_teasers, rss_plain, feed_length=10, feed_url=None, enclosure=None):
+
"""Takes all necessary data, and renders a RSS feed in output_path."""
+ rss_obj = rss.RSS2(
+ title=title,
+ link=link,
+ description=description,
+ lastBuildDate=datetime.datetime.now(),
+ generator='http://getnikola.com/',
+ language=lang
+ )
+
items = []
+
for post in timeline[:feed_length]:
- # Massage the post's HTML
- data = post.text(lang, teaser_only=rss_teasers, really_absolute=True)
+ old_url_type = self.config['URL_TYPE']
+ self.config['URL_TYPE'] = 'absolute'
+ data = post.text(lang, teaser_only=rss_teasers, strip_html=rss_plain, rss_read_more_link=True)
if feed_url is not None and data:
- # FIXME: this is duplicated with code in Post.text()
- try:
- doc = lxml.html.document_fromstring(data)
- doc.rewrite_links(lambda dst: self.url_replacer(feed_url, dst, lang))
+ # Massage the post's HTML (unless plain)
+ if not rss_plain:
+ # FIXME: this is duplicated with code in Post.text()
try:
- body = doc.body
- data = (body.text or '') + ''.join(
- [lxml.html.tostring(child, encoding='unicode')
- for child in body.iterchildren()])
- except IndexError: # No body there, it happens sometimes
- data = ''
- except lxml.etree.ParserError as e:
- if str(e) == "Document is empty":
- data = ""
- else: # let other errors raise
- raise(e)
-
+ doc = lxml.html.document_fromstring(data)
+ doc.rewrite_links(lambda dst: self.url_replacer(post.permalink(), dst, lang))
+ try:
+ body = doc.body
+ data = (body.text or '') + ''.join(
+ [lxml.html.tostring(child, encoding='unicode')
+ for child in body.iterchildren()])
+ except IndexError: # No body there, it happens sometimes
+ data = ''
+ except lxml.etree.ParserError as e:
+ if str(e) == "Document is empty":
+ data = ""
+ else: # let other errors raise
+ raise(e)
+ self.config['URL_TYPE'] = old_url_type
args = {
'title': post.title(lang),
'link': post.permalink(lang, absolute=True),
@@ -776,24 +920,28 @@ class Nikola(object):
'guid': post.permalink(lang, absolute=True),
# PyRSS2Gen's pubDate is GMT time.
'pubDate': (post.date if post.date.tzinfo is None else
- post.date.astimezone(pytz.timezone('UTC'))),
+ post.date.astimezone(dateutil.tz.tzutc())),
'categories': post._tags.get(lang, []),
- 'author': post.meta('author'),
+ 'creator': post.author(lang),
}
+ if post.author(lang):
+ rss_obj.rss_attrs["xmlns:dc"] = "http://purl.org/dc/elements/1.1/"
+
+ """ Enclosure callback must returns tuple """
+ if enclosure:
+ download_link, download_size, download_type = enclosure(post=post, lang=lang)
+
+ args['enclosure'] = rss.Enclosure(
+ download_link,
+ download_size,
+ download_type,
+ )
+
items.append(utils.ExtendedItem(**args))
- rss_obj = utils.ExtendedRSS2(
- title=title,
- link=link,
- description=description,
- lastBuildDate=datetime.datetime.now(),
- items=items,
- generator='Nikola <http://getnikola.com/>',
- language=lang
- )
- rss_obj.self_url = feed_url
- rss_obj.rss_attrs["xmlns:atom"] = "http://www.w3.org/2005/Atom"
- rss_obj.rss_attrs["xmlns:dc"] = "http://purl.org/dc/elements/1.1/"
+
+ rss_obj.items = items
+
dst_dir = os.path.dirname(output_path)
utils.makedirs(dst_dir)
with codecs.open(output_path, "wb+", "utf-8") as rss_file:
@@ -838,19 +986,23 @@ class Nikola(object):
if lang is None:
lang = utils.LocaleBorg().current_lang
- path = self.path_handlers[kind](name, lang)
- path = [os.path.normpath(p) for p in path if p != '.'] # Fix Issue #1028
-
- if is_link:
- link = '/' + ('/'.join(path))
- index_len = len(self.config['INDEX_FILE'])
- if self.config['STRIP_INDEXES'] and \
- link[-(1 + index_len):] == '/' + self.config['INDEX_FILE']:
- return link[:-index_len]
+ try:
+ path = self.path_handlers[kind](name, lang)
+ path = [os.path.normpath(p) for p in path if p != '.'] # Fix Issue #1028
+
+ if is_link:
+ link = '/' + ('/'.join(path))
+ index_len = len(self.config['INDEX_FILE'])
+ if self.config['STRIP_INDEXES'] and \
+ link[-(1 + index_len):] == '/' + self.config['INDEX_FILE']:
+ return link[:-index_len]
+ else:
+ return link
else:
- return link
- else:
- return os.path.join(*path)
+ return os.path.join(*path)
+ except KeyError:
+ utils.LOGGER.warn("Unknown path request of kind: {0}".format(kind))
+ return ""
def post_path(self, name, lang):
"""post_path path handler"""
@@ -862,7 +1014,7 @@ class Nikola(object):
"""slug path handler"""
results = [p for p in self.timeline if p.meta('slug') == name]
if not results:
- utils.LOGGER.warning("Can't resolve path request for slug: {0}".format(name))
+ utils.LOGGER.warning("Cannot resolve path request for slug: {0}".format(name))
else:
if len(results) > 1:
utils.LOGGER.warning('Ambiguous path request for slug: {0}'.format(name))
@@ -872,7 +1024,7 @@ class Nikola(object):
"""filename path handler"""
results = [p for p in self.timeline if p.source_path == name]
if not results:
- utils.LOGGER.warning("Can't resolve path request for filename: {0}".format(name))
+ utils.LOGGER.warning("Cannot resolve path request for filename: {0}".format(name))
else:
if len(results) > 1:
utils.LOGGER.error("Ambiguous path request for filename: {0}".format(name))
@@ -887,13 +1039,16 @@ class Nikola(object):
def link(self, *args):
return self.path(*args, is_link=True)
- def abs_link(self, dst):
+ def abs_link(self, dst, protocol_relative=False):
# Normalize
if dst: # Mako templates and empty strings evaluate to False
dst = urljoin(self.config['BASE_URL'], dst.lstrip('/'))
else:
dst = self.config['BASE_URL']
- return urlparse(dst).geturl()
+ url = urlparse(dst).geturl()
+ if protocol_relative:
+ url = url.split(":", 1)[1]
+ return url
def rel_link(self, src, dst):
# Normalize
@@ -967,40 +1122,55 @@ class Nikola(object):
'task_dep': task_dep
}
- def scan_posts(self):
+ def scan_posts(self, really=False):
"""Scan all the posts."""
- if self._scanned:
+ if self._scanned and not really:
return
+
+ self.commands = utils.Commands(self.doit)
+ self.global_data = {}
+ self.posts = []
+ self.posts_per_year = defaultdict(list)
+ self.posts_per_month = defaultdict(list)
+ self.posts_per_tag = defaultdict(list)
+ self.posts_per_category = defaultdict(list)
+ self.post_per_file = {}
+ self.timeline = []
+ self.pages = []
+
seen = set([])
- print("Scanning posts", end='', file=sys.stderr)
+ if not self.quiet:
+ print("Scanning posts", end='', file=sys.stderr)
slugged_tags = set([])
quit = False
for wildcard, destination, template_name, use_in_feeds in \
self.config['post_pages']:
- print(".", end='', file=sys.stderr)
+ if not self.quiet:
+ print(".", end='', file=sys.stderr)
dirname = os.path.dirname(wildcard)
- for dirpath, _, _ in os.walk(dirname):
- dir_glob = os.path.join(dirpath, os.path.basename(wildcard))
+ for dirpath, _, _ in os.walk(dirname, followlinks=True):
dest_dir = os.path.normpath(os.path.join(destination,
- os.path.relpath(dirpath, dirname)))
- full_list = glob.glob(dir_glob)
- # Now let's look for things that are not in default_lang
+ os.path.relpath(dirpath, dirname))) # output/destination/foo/
+ # Get all the untranslated paths
+ dir_glob = os.path.join(dirpath, os.path.basename(wildcard)) # posts/foo/*.rst
+ untranslated = glob.glob(dir_glob)
+ # And now get all the translated paths
+ translated = set([])
for lang in self.config['TRANSLATIONS'].keys():
- lang_glob = utils.get_translation_candidate(self.config, dir_glob, lang)
- translated_list = glob.glob(lang_glob)
- # dir_glob could have put it already in full_list
- full_list = list(set(full_list + translated_list))
-
- # Eliminate translations from full_list if they are not the primary,
- # or a secondary with no primary
- limited_list = full_list[:]
- for fname in full_list:
- for lang in self.config['TRANSLATIONS'].keys():
- translation = utils.get_translation_candidate(self.config, fname, lang)
- if translation in full_list:
- limited_list.remove(translation)
- full_list = limited_list
-
+ if lang == self.config['DEFAULT_LANG']:
+ continue
+ lang_glob = utils.get_translation_candidate(self.config, dir_glob, lang) # posts/foo/*.LANG.rst
+ translated = translated.union(set(glob.glob(lang_glob)))
+ # untranslated globs like *.rst often match translated paths too, so remove them
+ # and ensure x.rst is not in the translated set
+ untranslated = set(untranslated) - translated
+
+ # also remove from translated paths that are translations of
+ # paths in untranslated_list, so x.es.rst is not in the untranslated set
+ for p in untranslated:
+ translated = translated - set([utils.get_translation_candidate(self.config, p, l) for l in self.config['TRANSLATIONS'].keys()])
+
+ full_list = list(translated) + list(untranslated)
# We eliminate from the list the files inside any .ipynb folder
full_list = [p for p in full_list
if not any([x.startswith('.')
@@ -1020,13 +1190,14 @@ class Nikola(object):
template_name,
self.get_compiler(base_path)
)
+ self.timeline.append(post)
self.global_data[post.source_path] = post
if post.use_in_feeds:
- self.posts.append(post.source_path)
+ self.posts.append(post)
self.posts_per_year[
- str(post.date.year)].append(post.source_path)
+ str(post.date.year)].append(post)
self.posts_per_month[
- '{0}/{1:02d}'.format(post.date.year, post.date.month)].append(post.source_path)
+ '{0}/{1:02d}'.format(post.date.year, post.date.month)].append(post)
for tag in post.alltags:
if utils.slugify(tag) in slugged_tags:
if tag not in self.posts_per_tag:
@@ -1034,28 +1205,35 @@ class Nikola(object):
other_tag = [k for k in self.posts_per_tag.keys() if k.lower() == tag.lower()][0]
utils.LOGGER.error('You have tags that are too similar: {0} and {1}'.format(tag, other_tag))
utils.LOGGER.error('Tag {0} is used in: {1}'.format(tag, post.source_path))
- utils.LOGGER.error('Tag {0} is used in: {1}'.format(other_tag, ', '.join(self.posts_per_tag[other_tag])))
+ utils.LOGGER.error('Tag {0} is used in: {1}'.format(other_tag, ', '.join([p.source_path for p in self.posts_per_tag[other_tag]])))
quit = True
else:
slugged_tags.add(utils.slugify(tag))
- self.posts_per_tag[tag].append(post.source_path)
- self.posts_per_category[post.meta('category')].append(post.source_path)
+ self.posts_per_tag[tag].append(post)
+ self.posts_per_category[post.meta('category')].append(post)
else:
self.pages.append(post)
self.post_per_file[post.destination_path(lang=lang)] = post
self.post_per_file[post.destination_path(lang=lang, extension=post.source_ext())] = post
- for name, post in list(self.global_data.items()):
- self.timeline.append(post)
+ # Sort everything.
self.timeline.sort(key=lambda p: p.date)
self.timeline.reverse()
- post_timeline = [p for p in self.timeline if p.use_in_feeds]
- for i, p in enumerate(post_timeline[1:]):
- p.next_post = post_timeline[i]
- for i, p in enumerate(post_timeline[:-1]):
- p.prev_post = post_timeline[i + 1]
+ self.posts.sort(key=lambda p: p.date)
+ self.posts.reverse()
+ self.pages.sort(key=lambda p: p.date)
+ self.pages.reverse()
+
+ for i, p in enumerate(self.posts[1:]):
+ p.next_post = self.posts[i]
+ for i, p in enumerate(self.posts[:-1]):
+ p.prev_post = self.posts[i + 1]
self._scanned = True
- print("done!", file=sys.stderr)
+ if not self.quiet:
+ print("done!", file=sys.stderr)
+
+ signal('scanned').send(self)
+
if quit:
sys.exit(1)
@@ -1089,6 +1267,13 @@ class Nikola(object):
deps_dict['TRANSLATIONS'] = self.config['TRANSLATIONS']
deps_dict['global'] = self.GLOBAL_CONTEXT
deps_dict['comments'] = context['enable_comments']
+
+ for k, v in self.GLOBAL_CONTEXT['template_hooks'].items():
+ deps_dict['||template_hooks|{0}||'.format(k)] = v._items
+
+ for k in self._GLOBAL_CONTEXT_TRANSLATABLE:
+ deps_dict[k] = deps_dict['global'][k](lang)
+
if post:
deps_dict['post_translations'] = post.translated_to
@@ -1113,8 +1298,8 @@ class Nikola(object):
deps += post.deps(lang)
context = {}
context["posts"] = posts
- context["title"] = self.config['BLOG_TITLE']
- context["description"] = self.config['BLOG_DESCRIPTION']
+ context["title"] = self.config['BLOG_TITLE'](lang)
+ context["description"] = self.config['BLOG_DESCRIPTION'](lang)
context["lang"] = lang
context["prevlink"] = None
context["nextlink"] = None
@@ -1123,6 +1308,13 @@ class Nikola(object):
deps_context["posts"] = [(p.meta[lang]['title'], p.permalink(lang)) for p in
posts]
deps_context["global"] = self.GLOBAL_CONTEXT
+
+ for k, v in self.GLOBAL_CONTEXT['template_hooks'].items():
+ deps_context['||template_hooks|{0}||'.format(k)] = v._items
+
+ for k in self._GLOBAL_CONTEXT_TRANSLATABLE:
+ deps_context[k] = deps_context['global'][k](lang)
+
task = {
'name': os.path.normpath(output_name),
'targets': [output_name],
@@ -1135,6 +1327,9 @@ class Nikola(object):
return utils.apply_filters(task, filters)
+ def __repr__(self):
+ return '<Nikola Site: {0!r}>'.format(self.config['BLOG_TITLE']())
+
def sanitized_locales(locale_fallback, locale_default, locales, translations):
"""Sanitizes all locales availble into a nikola session
@@ -1297,7 +1492,7 @@ _windows_locale_guesses = {
"en": "English",
"eo": "Esperanto",
"es": "Spanish",
- "fa": "Farsi", # persian
+ "fa": "Farsi", # Persian
"fr": "French",
"hr": "Croatian",
"it": "Italian",
@@ -1322,6 +1517,6 @@ SOCIAL_BUTTONS_CODE = """
<li><a class="addthis_button_twitter"></a>
</ul>
</div>
-<script type="text/javascript" src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script>
+<script src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script>
<!-- End of social buttons -->
"""
diff --git a/nikola/packages/README.md b/nikola/packages/README.md
new file mode 100644
index 0000000..156d43f
--- /dev/null
+++ b/nikola/packages/README.md
@@ -0,0 +1,5 @@
+We ship some third-party things with Nikola. They live here, along with their licenses.
+
+Packages:
+
+ * tzlocal by Lennart Regebro, CC0 license (modified)
diff --git a/nikola/packages/__init__.py b/nikola/packages/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nikola/packages/__init__.py
diff --git a/nikola/packages/tzlocal/LICENSE.txt b/nikola/packages/tzlocal/LICENSE.txt
new file mode 100644
index 0000000..0e259d4
--- /dev/null
+++ b/nikola/packages/tzlocal/LICENSE.txt
@@ -0,0 +1,121 @@
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+ HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
diff --git a/nikola/packages/tzlocal/__init__.py b/nikola/packages/tzlocal/__init__.py
new file mode 100644
index 0000000..10716ec
--- /dev/null
+++ b/nikola/packages/tzlocal/__init__.py
@@ -0,0 +1,7 @@
+import sys
+if sys.platform == 'win32':
+ from .win32 import get_localzone, reload_localzone # NOQA
+elif 'darwin' in sys.platform:
+ from .darwin import get_localzone, reload_localzone # NOQA
+else:
+ from .unix import get_localzone, reload_localzone # NOQA
diff --git a/nikola/packages/tzlocal/darwin.py b/nikola/packages/tzlocal/darwin.py
new file mode 100644
index 0000000..8aeee51
--- /dev/null
+++ b/nikola/packages/tzlocal/darwin.py
@@ -0,0 +1,33 @@
+from __future__ import with_statement
+import os
+import dateutil.tz
+
+_cache_tz = None
+
+
+def _get_localzone():
+ tzname = os.popen("systemsetup -gettimezone").read().replace("Time Zone: ", "").strip()
+ if not tzname:
+ # link will be something like /usr/share/zoneinfo/America/Los_Angeles.
+ link = os.readlink("/etc/localtime")
+ tzname = link[link.rfind('/', 0, link.rfind('/')) + 1:]
+ try:
+ dateutil.tz.gettz(tzname)
+ return tzname
+ except:
+ return None
+
+
+def get_localzone():
+ """Get the computers configured local timezone, if any."""
+ global _cache_tz
+ if _cache_tz is None:
+ _cache_tz = _get_localzone()
+ return _cache_tz
+
+
+def reload_localzone():
+ """Reload the cached localzone. You need to call this if the timezone has changed."""
+ global _cache_tz
+ _cache_tz = _get_localzone()
+ return _cache_tz
diff --git a/nikola/packages/tzlocal/unix.py b/nikola/packages/tzlocal/unix.py
new file mode 100644
index 0000000..8e913b8
--- /dev/null
+++ b/nikola/packages/tzlocal/unix.py
@@ -0,0 +1,126 @@
+from __future__ import with_statement
+import os
+import re
+import dateutil.tz
+
+_cache_tz = None
+
+
+def _get_localzone():
+ """Tries to find the local timezone configuration.
+
+ This method prefers finding the timezone name and passing that to pytz,
+ over passing in the localtime file, as in the later case the zoneinfo
+ name is unknown.
+
+ The parameter _root makes the function look for files like /etc/localtime
+ beneath the _root directory. This is primarily used by the tests.
+ In normal usage you call the function without parameters."""
+
+ tz = os.environ.get('TZ')
+ if tz and tz[0] == ':':
+ tz = tz[1:]
+ try:
+ if tz:
+ dateutil.tz.gettz(tz)
+ return tz
+ except:
+ pass
+
+ try:
+ # link will be something like /usr/share/zoneinfo/America/Los_Angeles.
+ link = os.readlink('/etc/localtime')
+ tz = link[link.rfind('/', 0, link.rfind('/')) + 1:]
+
+ if tz:
+ dateutil.tz.gettz(tz)
+ return tz
+ except:
+ return None
+
+ # Now look for distribution specific configuration files
+ # that contain the timezone name.
+ tzpath = os.path.join('/etc/timezone')
+ if os.path.exists(tzpath):
+ with open(tzpath, 'rb') as tzfile:
+ data = tzfile.read()
+
+ # Issue #3 was that /etc/timezone was a zoneinfo file.
+ # That's a misconfiguration, but we need to handle it gracefully:
+ if data[:5] != 'TZif2':
+ etctz = data.strip().decode()
+ # Get rid of host definitions and comments:
+ if ' ' in etctz:
+ etctz, dummy = etctz.split(' ', 1)
+ if '#' in etctz:
+ etctz, dummy = etctz.split('#', 1)
+ tz = etctz.replace(' ', '_')
+ try:
+ if tz:
+ dateutil.tz.gettz(tz)
+ return tz
+ except:
+ pass
+
+ # CentOS has a ZONE setting in /etc/sysconfig/clock,
+ # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and
+ # Gentoo has a TIMEZONE setting in /etc/conf.d/clock
+ # We look through these files for a timezone:
+
+ zone_re = re.compile('\s*ZONE\s*=\s*\"')
+ timezone_re = re.compile('\s*TIMEZONE\s*=\s*\"')
+ end_re = re.compile('\"')
+
+ for tzpath in ('/etc/sysconfig/clock', '/etc/conf.d/clock'):
+ if not os.path.exists(tzpath):
+ continue
+ with open(tzpath, 'rt') as tzfile:
+ data = tzfile.readlines()
+
+ for line in data:
+ # Look for the ZONE= setting.
+ match = zone_re.match(line)
+ if match is None:
+ # No ZONE= setting. Look for the TIMEZONE= setting.
+ match = timezone_re.match(line)
+ if match is not None:
+ # Some setting existed
+ line = line[match.end():]
+ etctz = line[:end_re.search(line).start()]
+
+ # We found a timezone
+ tz = etctz.replace(' ', '_')
+ try:
+ if tz:
+ dateutil.tz.gettz(tz)
+ return tz
+ except:
+ pass
+
+ # Nikola cannot use this thing below...
+
+ # No explicit setting existed. Use localtime
+ # for filename in ('etc/localtime', 'usr/local/etc/localtime'):
+ # tzpath = os.path.join(_root, filename)
+
+ # if not os.path.exists(tzpath):
+ # continue
+ # with open(tzpath, 'rb') as tzfile:
+ # return pytz.tzfile.build_tzinfo('local', tzfile)
+
+ return None
+
+
+def get_localzone():
+ """Get the computers configured local timezone, if any."""
+ global _cache_tz
+ if _cache_tz is None:
+ _cache_tz = _get_localzone()
+ return _cache_tz
+
+
+def reload_localzone():
+ """Reload the cached localzone. You need to call this if the timezone has changed."""
+ global _cache_tz
+ _cache_tz = _get_localzone()
+ return _cache_tz
diff --git a/nikola/packages/tzlocal/win32.py b/nikola/packages/tzlocal/win32.py
new file mode 100644
index 0000000..7005422
--- /dev/null
+++ b/nikola/packages/tzlocal/win32.py
@@ -0,0 +1,92 @@
+try:
+ import _winreg as winreg
+except ImportError:
+ try:
+ import winreg
+ except ImportError:
+ pass # not windows
+
+from .windows_tz import win_tz
+
+_cache_tz = None
+
+
+def valuestodict(key):
+ """Convert a registry key's values to a dictionary."""
+ dict = {}
+ size = winreg.QueryInfoKey(key)[1]
+ for i in range(size):
+ data = winreg.EnumValue(key, i)
+ dict[data[0]] = data[1]
+ return dict
+
+
+def get_localzone_name():
+ # Windows is special. It has unique time zone names (in several
+ # meanings of the word) available, but unfortunately, they can be
+ # translated to the language of the operating system, so we need to
+ # do a backwards lookup, by going through all time zones and see which
+ # one matches.
+ handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
+
+ TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
+ localtz = winreg.OpenKey(handle, TZLOCALKEYNAME)
+ keyvalues = valuestodict(localtz)
+ localtz.Close()
+ if 'TimeZoneKeyName' in keyvalues:
+ # Windows 7 (and Vista?)
+
+ # For some reason this returns a string with loads of NUL bytes at
+ # least on some systems. I don't know if this is a bug somewhere, I
+ # just work around it.
+ tzkeyname = keyvalues['TimeZoneKeyName'].split('\x00', 1)[0]
+ else:
+ # Windows 2000 or XP
+
+ # This is the localized name:
+ tzwin = keyvalues['StandardName']
+
+ # Open the list of timezones to look up the real name:
+ TZKEYNAME = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
+ tzkey = winreg.OpenKey(handle, TZKEYNAME)
+
+ # Now, match this value to Time Zone information
+ tzkeyname = None
+ for i in range(winreg.QueryInfoKey(tzkey)[0]):
+ subkey = winreg.EnumKey(tzkey, i)
+ sub = winreg.OpenKey(tzkey, subkey)
+ data = valuestodict(sub)
+ sub.Close()
+ if data['Std'] == tzwin:
+ tzkeyname = subkey
+ break
+
+ tzkey.Close()
+ handle.Close()
+
+ if tzkeyname is None:
+ raise LookupError('Can not find Windows timezone configuration')
+
+ timezone = win_tz.get(tzkeyname)
+ if timezone is None:
+ # Nope, that didn't work. Try adding "Standard Time",
+ # it seems to work a lot of times:
+ timezone = win_tz.get(tzkeyname + " Standard Time")
+
+ # Return what we have.
+ return timezone
+
+
+def get_localzone():
+ """Returns the zoneinfo-based tzinfo object that matches the Windows-configured timezone."""
+ global _cache_tz
+ if _cache_tz is None:
+ _cache_tz = get_localzone_name()
+ return _cache_tz
+
+
+def reload_localzone():
+ """Reload the cached localzone. You need to call this if the timezone has changed."""
+ global _cache_tz
+ _cache_tz = get_localzone_name()
+ return _cache_tz
diff --git a/nikola/packages/tzlocal/windows_tz.py b/nikola/packages/tzlocal/windows_tz.py
new file mode 100644
index 0000000..1084478
--- /dev/null
+++ b/nikola/packages/tzlocal/windows_tz.py
@@ -0,0 +1,543 @@
+# This file is autogenerated by the get_windows_info.py script
+# Do not edit.
+win_tz = {
+ 'AUS Central Standard Time': 'Australia/Darwin',
+ 'AUS Eastern Standard Time': 'Australia/Sydney',
+ 'Afghanistan Standard Time': 'Asia/Kabul',
+ 'Alaskan Standard Time': 'America/Anchorage',
+ 'Arab Standard Time': 'Asia/Riyadh',
+ 'Arabian Standard Time': 'Asia/Dubai',
+ 'Arabic Standard Time': 'Asia/Baghdad',
+ 'Argentina Standard Time': 'America/Buenos_Aires',
+ 'Atlantic Standard Time': 'America/Halifax',
+ 'Azerbaijan Standard Time': 'Asia/Baku',
+ 'Azores Standard Time': 'Atlantic/Azores',
+ 'Bahia Standard Time': 'America/Bahia',
+ 'Bangladesh Standard Time': 'Asia/Dhaka',
+ 'Canada Central Standard Time': 'America/Regina',
+ 'Cape Verde Standard Time': 'Atlantic/Cape_Verde',
+ 'Caucasus Standard Time': 'Asia/Yerevan',
+ 'Cen. Australia Standard Time': 'Australia/Adelaide',
+ 'Central America Standard Time': 'America/Guatemala',
+ 'Central Asia Standard Time': 'Asia/Almaty',
+ 'Central Brazilian Standard Time': 'America/Cuiaba',
+ 'Central Europe Standard Time': 'Europe/Budapest',
+ 'Central European Standard Time': 'Europe/Warsaw',
+ 'Central Pacific Standard Time': 'Pacific/Guadalcanal',
+ 'Central Standard Time': 'America/Chicago',
+ 'Central Standard Time (Mexico)': 'America/Mexico_City',
+ 'China Standard Time': 'Asia/Shanghai',
+ 'Dateline Standard Time': 'Etc/GMT+12',
+ 'E. Africa Standard Time': 'Africa/Nairobi',
+ 'E. Australia Standard Time': 'Australia/Brisbane',
+ 'E. Europe Standard Time': 'Asia/Nicosia',
+ 'E. South America Standard Time': 'America/Sao_Paulo',
+ 'Eastern Standard Time': 'America/New_York',
+ 'Egypt Standard Time': 'Africa/Cairo',
+ 'Ekaterinburg Standard Time': 'Asia/Yekaterinburg',
+ 'FLE Standard Time': 'Europe/Kiev',
+ 'Fiji Standard Time': 'Pacific/Fiji',
+ 'GMT Standard Time': 'Europe/London',
+ 'GTB Standard Time': 'Europe/Bucharest',
+ 'Georgian Standard Time': 'Asia/Tbilisi',
+ 'Greenland Standard Time': 'America/Godthab',
+ 'Greenwich Standard Time': 'Atlantic/Reykjavik',
+ 'Hawaiian Standard Time': 'Pacific/Honolulu',
+ 'India Standard Time': 'Asia/Calcutta',
+ 'Iran Standard Time': 'Asia/Tehran',
+ 'Israel Standard Time': 'Asia/Jerusalem',
+ 'Jordan Standard Time': 'Asia/Amman',
+ 'Kaliningrad Standard Time': 'Europe/Kaliningrad',
+ 'Korea Standard Time': 'Asia/Seoul',
+ 'Libya Standard Time': 'Africa/Tripoli',
+ 'Magadan Standard Time': 'Asia/Magadan',
+ 'Mauritius Standard Time': 'Indian/Mauritius',
+ 'Middle East Standard Time': 'Asia/Beirut',
+ 'Montevideo Standard Time': 'America/Montevideo',
+ 'Morocco Standard Time': 'Africa/Casablanca',
+ 'Mountain Standard Time': 'America/Denver',
+ 'Mountain Standard Time (Mexico)': 'America/Chihuahua',
+ 'Myanmar Standard Time': 'Asia/Rangoon',
+ 'N. Central Asia Standard Time': 'Asia/Novosibirsk',
+ 'Namibia Standard Time': 'Africa/Windhoek',
+ 'Nepal Standard Time': 'Asia/Katmandu',
+ 'New Zealand Standard Time': 'Pacific/Auckland',
+ 'Newfoundland Standard Time': 'America/St_Johns',
+ 'North Asia East Standard Time': 'Asia/Irkutsk',
+ 'North Asia Standard Time': 'Asia/Krasnoyarsk',
+ 'Pacific SA Standard Time': 'America/Santiago',
+ 'Pacific Standard Time': 'America/Los_Angeles',
+ 'Pacific Standard Time (Mexico)': 'America/Santa_Isabel',
+ 'Pakistan Standard Time': 'Asia/Karachi',
+ 'Paraguay Standard Time': 'America/Asuncion',
+ 'Romance Standard Time': 'Europe/Paris',
+ 'Russian Standard Time': 'Europe/Moscow',
+ 'SA Eastern Standard Time': 'America/Cayenne',
+ 'SA Pacific Standard Time': 'America/Bogota',
+ 'SA Western Standard Time': 'America/La_Paz',
+ 'SE Asia Standard Time': 'Asia/Bangkok',
+ 'Samoa Standard Time': 'Pacific/Apia',
+ 'Singapore Standard Time': 'Asia/Singapore',
+ 'South Africa Standard Time': 'Africa/Johannesburg',
+ 'Sri Lanka Standard Time': 'Asia/Colombo',
+ 'Syria Standard Time': 'Asia/Damascus',
+ 'Taipei Standard Time': 'Asia/Taipei',
+ 'Tasmania Standard Time': 'Australia/Hobart',
+ 'Tokyo Standard Time': 'Asia/Tokyo',
+ 'Tonga Standard Time': 'Pacific/Tongatapu',
+ 'Turkey Standard Time': 'Europe/Istanbul',
+ 'US Eastern Standard Time': 'America/Indianapolis',
+ 'US Mountain Standard Time': 'America/Phoenix',
+ 'UTC': 'Etc/GMT',
+ 'UTC+12': 'Etc/GMT-12',
+ 'UTC-02': 'Etc/GMT+2',
+ 'UTC-11': 'Etc/GMT+11',
+ 'Ulaanbaatar Standard Time': 'Asia/Ulaanbaatar',
+ 'Venezuela Standard Time': 'America/Caracas',
+ 'Vladivostok Standard Time': 'Asia/Vladivostok',
+ 'W. Australia Standard Time': 'Australia/Perth',
+ 'W. Central Africa Standard Time': 'Africa/Lagos',
+ 'W. Europe Standard Time': 'Europe/Berlin',
+ 'West Asia Standard Time': 'Asia/Tashkent',
+ 'West Pacific Standard Time': 'Pacific/Port_Moresby',
+ 'Yakutsk Standard Time': 'Asia/Yakutsk'
+}
+
+# Old name for the win_tz variable:
+tz_names = win_tz
+
+tz_win = {
+ 'Africa/Abidjan': 'Greenwich Standard Time',
+ 'Africa/Accra': 'Greenwich Standard Time',
+ 'Africa/Addis_Ababa': 'E. Africa Standard Time',
+ 'Africa/Algiers': 'W. Central Africa Standard Time',
+ 'Africa/Asmera': 'E. Africa Standard Time',
+ 'Africa/Bamako': 'Greenwich Standard Time',
+ 'Africa/Bangui': 'W. Central Africa Standard Time',
+ 'Africa/Banjul': 'Greenwich Standard Time',
+ 'Africa/Bissau': 'Greenwich Standard Time',
+ 'Africa/Blantyre': 'South Africa Standard Time',
+ 'Africa/Brazzaville': 'W. Central Africa Standard Time',
+ 'Africa/Bujumbura': 'South Africa Standard Time',
+ 'Africa/Cairo': 'Egypt Standard Time',
+ 'Africa/Casablanca': 'Morocco Standard Time',
+ 'Africa/Ceuta': 'Romance Standard Time',
+ 'Africa/Conakry': 'Greenwich Standard Time',
+ 'Africa/Dakar': 'Greenwich Standard Time',
+ 'Africa/Dar_es_Salaam': 'E. Africa Standard Time',
+ 'Africa/Djibouti': 'E. Africa Standard Time',
+ 'Africa/Douala': 'W. Central Africa Standard Time',
+ 'Africa/El_Aaiun': 'Morocco Standard Time',
+ 'Africa/Freetown': 'Greenwich Standard Time',
+ 'Africa/Gaborone': 'South Africa Standard Time',
+ 'Africa/Harare': 'South Africa Standard Time',
+ 'Africa/Johannesburg': 'South Africa Standard Time',
+ 'Africa/Juba': 'E. Africa Standard Time',
+ 'Africa/Kampala': 'E. Africa Standard Time',
+ 'Africa/Khartoum': 'E. Africa Standard Time',
+ 'Africa/Kigali': 'South Africa Standard Time',
+ 'Africa/Kinshasa': 'W. Central Africa Standard Time',
+ 'Africa/Lagos': 'W. Central Africa Standard Time',
+ 'Africa/Libreville': 'W. Central Africa Standard Time',
+ 'Africa/Lome': 'Greenwich Standard Time',
+ 'Africa/Luanda': 'W. Central Africa Standard Time',
+ 'Africa/Lubumbashi': 'South Africa Standard Time',
+ 'Africa/Lusaka': 'South Africa Standard Time',
+ 'Africa/Malabo': 'W. Central Africa Standard Time',
+ 'Africa/Maputo': 'South Africa Standard Time',
+ 'Africa/Maseru': 'South Africa Standard Time',
+ 'Africa/Mbabane': 'South Africa Standard Time',
+ 'Africa/Mogadishu': 'E. Africa Standard Time',
+ 'Africa/Monrovia': 'Greenwich Standard Time',
+ 'Africa/Nairobi': 'E. Africa Standard Time',
+ 'Africa/Ndjamena': 'W. Central Africa Standard Time',
+ 'Africa/Niamey': 'W. Central Africa Standard Time',
+ 'Africa/Nouakchott': 'Greenwich Standard Time',
+ 'Africa/Ouagadougou': 'Greenwich Standard Time',
+ 'Africa/Porto-Novo': 'W. Central Africa Standard Time',
+ 'Africa/Sao_Tome': 'Greenwich Standard Time',
+ 'Africa/Tripoli': 'Libya Standard Time',
+ 'Africa/Tunis': 'W. Central Africa Standard Time',
+ 'Africa/Windhoek': 'Namibia Standard Time',
+ 'America/Anchorage': 'Alaskan Standard Time',
+ 'America/Anguilla': 'SA Western Standard Time',
+ 'America/Antigua': 'SA Western Standard Time',
+ 'America/Araguaina': 'SA Eastern Standard Time',
+ 'America/Argentina/La_Rioja': 'Argentina Standard Time',
+ 'America/Argentina/Rio_Gallegos': 'Argentina Standard Time',
+ 'America/Argentina/Salta': 'Argentina Standard Time',
+ 'America/Argentina/San_Juan': 'Argentina Standard Time',
+ 'America/Argentina/San_Luis': 'Argentina Standard Time',
+ 'America/Argentina/Tucuman': 'Argentina Standard Time',
+ 'America/Argentina/Ushuaia': 'Argentina Standard Time',
+ 'America/Aruba': 'SA Western Standard Time',
+ 'America/Asuncion': 'Paraguay Standard Time',
+ 'America/Bahia': 'Bahia Standard Time',
+ 'America/Bahia_Banderas': 'Central Standard Time (Mexico)',
+ 'America/Barbados': 'SA Western Standard Time',
+ 'America/Belem': 'SA Eastern Standard Time',
+ 'America/Belize': 'Central America Standard Time',
+ 'America/Blanc-Sablon': 'SA Western Standard Time',
+ 'America/Boa_Vista': 'SA Western Standard Time',
+ 'America/Bogota': 'SA Pacific Standard Time',
+ 'America/Boise': 'Mountain Standard Time',
+ 'America/Buenos_Aires': 'Argentina Standard Time',
+ 'America/Cambridge_Bay': 'Mountain Standard Time',
+ 'America/Campo_Grande': 'Central Brazilian Standard Time',
+ 'America/Cancun': 'Central Standard Time (Mexico)',
+ 'America/Caracas': 'Venezuela Standard Time',
+ 'America/Catamarca': 'Argentina Standard Time',
+ 'America/Cayenne': 'SA Eastern Standard Time',
+ 'America/Cayman': 'SA Pacific Standard Time',
+ 'America/Chicago': 'Central Standard Time',
+ 'America/Chihuahua': 'Mountain Standard Time (Mexico)',
+ 'America/Coral_Harbour': 'SA Pacific Standard Time',
+ 'America/Cordoba': 'Argentina Standard Time',
+ 'America/Costa_Rica': 'Central America Standard Time',
+ 'America/Creston': 'US Mountain Standard Time',
+ 'America/Cuiaba': 'Central Brazilian Standard Time',
+ 'America/Curacao': 'SA Western Standard Time',
+ 'America/Danmarkshavn': 'UTC',
+ 'America/Dawson': 'Pacific Standard Time',
+ 'America/Dawson_Creek': 'US Mountain Standard Time',
+ 'America/Denver': 'Mountain Standard Time',
+ 'America/Detroit': 'Eastern Standard Time',
+ 'America/Dominica': 'SA Western Standard Time',
+ 'America/Edmonton': 'Mountain Standard Time',
+ 'America/Eirunepe': 'SA Pacific Standard Time',
+ 'America/El_Salvador': 'Central America Standard Time',
+ 'America/Fortaleza': 'SA Eastern Standard Time',
+ 'America/Glace_Bay': 'Atlantic Standard Time',
+ 'America/Godthab': 'Greenland Standard Time',
+ 'America/Goose_Bay': 'Atlantic Standard Time',
+ 'America/Grand_Turk': 'Eastern Standard Time',
+ 'America/Grenada': 'SA Western Standard Time',
+ 'America/Guadeloupe': 'SA Western Standard Time',
+ 'America/Guatemala': 'Central America Standard Time',
+ 'America/Guayaquil': 'SA Pacific Standard Time',
+ 'America/Guyana': 'SA Western Standard Time',
+ 'America/Halifax': 'Atlantic Standard Time',
+ 'America/Havana': 'Eastern Standard Time',
+ 'America/Hermosillo': 'US Mountain Standard Time',
+ 'America/Indiana/Knox': 'Central Standard Time',
+ 'America/Indiana/Marengo': 'US Eastern Standard Time',
+ 'America/Indiana/Petersburg': 'Eastern Standard Time',
+ 'America/Indiana/Tell_City': 'Central Standard Time',
+ 'America/Indiana/Vevay': 'US Eastern Standard Time',
+ 'America/Indiana/Vincennes': 'Eastern Standard Time',
+ 'America/Indiana/Winamac': 'Eastern Standard Time',
+ 'America/Indianapolis': 'US Eastern Standard Time',
+ 'America/Inuvik': 'Mountain Standard Time',
+ 'America/Iqaluit': 'Eastern Standard Time',
+ 'America/Jamaica': 'SA Pacific Standard Time',
+ 'America/Jujuy': 'Argentina Standard Time',
+ 'America/Juneau': 'Alaskan Standard Time',
+ 'America/Kentucky/Monticello': 'Eastern Standard Time',
+ 'America/Kralendijk': 'SA Western Standard Time',
+ 'America/La_Paz': 'SA Western Standard Time',
+ 'America/Lima': 'SA Pacific Standard Time',
+ 'America/Los_Angeles': 'Pacific Standard Time',
+ 'America/Louisville': 'Eastern Standard Time',
+ 'America/Lower_Princes': 'SA Western Standard Time',
+ 'America/Maceio': 'SA Eastern Standard Time',
+ 'America/Managua': 'Central America Standard Time',
+ 'America/Manaus': 'SA Western Standard Time',
+ 'America/Marigot': 'SA Western Standard Time',
+ 'America/Martinique': 'SA Western Standard Time',
+ 'America/Matamoros': 'Central Standard Time',
+ 'America/Mazatlan': 'Mountain Standard Time (Mexico)',
+ 'America/Mendoza': 'Argentina Standard Time',
+ 'America/Menominee': 'Central Standard Time',
+ 'America/Merida': 'Central Standard Time (Mexico)',
+ 'America/Mexico_City': 'Central Standard Time (Mexico)',
+ 'America/Moncton': 'Atlantic Standard Time',
+ 'America/Monterrey': 'Central Standard Time (Mexico)',
+ 'America/Montevideo': 'Montevideo Standard Time',
+ 'America/Montreal': 'Eastern Standard Time',
+ 'America/Montserrat': 'SA Western Standard Time',
+ 'America/Nassau': 'Eastern Standard Time',
+ 'America/New_York': 'Eastern Standard Time',
+ 'America/Nipigon': 'Eastern Standard Time',
+ 'America/Nome': 'Alaskan Standard Time',
+ 'America/Noronha': 'UTC-02',
+ 'America/North_Dakota/Beulah': 'Central Standard Time',
+ 'America/North_Dakota/Center': 'Central Standard Time',
+ 'America/North_Dakota/New_Salem': 'Central Standard Time',
+ 'America/Ojinaga': 'Mountain Standard Time',
+ 'America/Panama': 'SA Pacific Standard Time',
+ 'America/Pangnirtung': 'Eastern Standard Time',
+ 'America/Paramaribo': 'SA Eastern Standard Time',
+ 'America/Phoenix': 'US Mountain Standard Time',
+ 'America/Port-au-Prince': 'Eastern Standard Time',
+ 'America/Port_of_Spain': 'SA Western Standard Time',
+ 'America/Porto_Velho': 'SA Western Standard Time',
+ 'America/Puerto_Rico': 'SA Western Standard Time',
+ 'America/Rainy_River': 'Central Standard Time',
+ 'America/Rankin_Inlet': 'Central Standard Time',
+ 'America/Recife': 'SA Eastern Standard Time',
+ 'America/Regina': 'Canada Central Standard Time',
+ 'America/Resolute': 'Central Standard Time',
+ 'America/Rio_Branco': 'SA Pacific Standard Time',
+ 'America/Santa_Isabel': 'Pacific Standard Time (Mexico)',
+ 'America/Santarem': 'SA Eastern Standard Time',
+ 'America/Santiago': 'Pacific SA Standard Time',
+ 'America/Santo_Domingo': 'SA Western Standard Time',
+ 'America/Sao_Paulo': 'E. South America Standard Time',
+ 'America/Scoresbysund': 'Azores Standard Time',
+ 'America/Shiprock': 'Mountain Standard Time',
+ 'America/Sitka': 'Alaskan Standard Time',
+ 'America/St_Barthelemy': 'SA Western Standard Time',
+ 'America/St_Johns': 'Newfoundland Standard Time',
+ 'America/St_Kitts': 'SA Western Standard Time',
+ 'America/St_Lucia': 'SA Western Standard Time',
+ 'America/St_Thomas': 'SA Western Standard Time',
+ 'America/St_Vincent': 'SA Western Standard Time',
+ 'America/Swift_Current': 'Canada Central Standard Time',
+ 'America/Tegucigalpa': 'Central America Standard Time',
+ 'America/Thule': 'Atlantic Standard Time',
+ 'America/Thunder_Bay': 'Eastern Standard Time',
+ 'America/Tijuana': 'Pacific Standard Time',
+ 'America/Toronto': 'Eastern Standard Time',
+ 'America/Tortola': 'SA Western Standard Time',
+ 'America/Vancouver': 'Pacific Standard Time',
+ 'America/Whitehorse': 'Pacific Standard Time',
+ 'America/Winnipeg': 'Central Standard Time',
+ 'America/Yakutat': 'Alaskan Standard Time',
+ 'America/Yellowknife': 'Mountain Standard Time',
+ 'Antarctica/Casey': 'W. Australia Standard Time',
+ 'Antarctica/Davis': 'SE Asia Standard Time',
+ 'Antarctica/DumontDUrville': 'West Pacific Standard Time',
+ 'Antarctica/Macquarie': 'Central Pacific Standard Time',
+ 'Antarctica/Mawson': 'West Asia Standard Time',
+ 'Antarctica/McMurdo': 'New Zealand Standard Time',
+ 'Antarctica/Palmer': 'Pacific SA Standard Time',
+ 'Antarctica/Rothera': 'SA Eastern Standard Time',
+ 'Antarctica/South_Pole': 'New Zealand Standard Time',
+ 'Antarctica/Syowa': 'E. Africa Standard Time',
+ 'Antarctica/Vostok': 'Central Asia Standard Time',
+ 'Arctic/Longyearbyen': 'W. Europe Standard Time',
+ 'Asia/Aden': 'Arab Standard Time',
+ 'Asia/Almaty': 'Central Asia Standard Time',
+ 'Asia/Amman': 'Jordan Standard Time',
+ 'Asia/Anadyr': 'Magadan Standard Time',
+ 'Asia/Aqtau': 'West Asia Standard Time',
+ 'Asia/Aqtobe': 'West Asia Standard Time',
+ 'Asia/Ashgabat': 'West Asia Standard Time',
+ 'Asia/Baghdad': 'Arabic Standard Time',
+ 'Asia/Bahrain': 'Arab Standard Time',
+ 'Asia/Baku': 'Azerbaijan Standard Time',
+ 'Asia/Bangkok': 'SE Asia Standard Time',
+ 'Asia/Beirut': 'Middle East Standard Time',
+ 'Asia/Bishkek': 'Central Asia Standard Time',
+ 'Asia/Brunei': 'Singapore Standard Time',
+ 'Asia/Calcutta': 'India Standard Time',
+ 'Asia/Choibalsan': 'Ulaanbaatar Standard Time',
+ 'Asia/Chongqing': 'China Standard Time',
+ 'Asia/Colombo': 'Sri Lanka Standard Time',
+ 'Asia/Damascus': 'Syria Standard Time',
+ 'Asia/Dhaka': 'Bangladesh Standard Time',
+ 'Asia/Dili': 'Tokyo Standard Time',
+ 'Asia/Dubai': 'Arabian Standard Time',
+ 'Asia/Dushanbe': 'West Asia Standard Time',
+ 'Asia/Harbin': 'China Standard Time',
+ 'Asia/Hong_Kong': 'China Standard Time',
+ 'Asia/Hovd': 'SE Asia Standard Time',
+ 'Asia/Irkutsk': 'North Asia East Standard Time',
+ 'Asia/Jakarta': 'SE Asia Standard Time',
+ 'Asia/Jayapura': 'Tokyo Standard Time',
+ 'Asia/Jerusalem': 'Israel Standard Time',
+ 'Asia/Kabul': 'Afghanistan Standard Time',
+ 'Asia/Kamchatka': 'Magadan Standard Time',
+ 'Asia/Karachi': 'Pakistan Standard Time',
+ 'Asia/Kashgar': 'China Standard Time',
+ 'Asia/Katmandu': 'Nepal Standard Time',
+ 'Asia/Khandyga': 'Yakutsk Standard Time',
+ 'Asia/Krasnoyarsk': 'North Asia Standard Time',
+ 'Asia/Kuala_Lumpur': 'Singapore Standard Time',
+ 'Asia/Kuching': 'Singapore Standard Time',
+ 'Asia/Kuwait': 'Arab Standard Time',
+ 'Asia/Macau': 'China Standard Time',
+ 'Asia/Magadan': 'Magadan Standard Time',
+ 'Asia/Makassar': 'Singapore Standard Time',
+ 'Asia/Manila': 'Singapore Standard Time',
+ 'Asia/Muscat': 'Arabian Standard Time',
+ 'Asia/Nicosia': 'E. Europe Standard Time',
+ 'Asia/Novokuznetsk': 'N. Central Asia Standard Time',
+ 'Asia/Novosibirsk': 'N. Central Asia Standard Time',
+ 'Asia/Omsk': 'N. Central Asia Standard Time',
+ 'Asia/Oral': 'West Asia Standard Time',
+ 'Asia/Phnom_Penh': 'SE Asia Standard Time',
+ 'Asia/Pontianak': 'SE Asia Standard Time',
+ 'Asia/Pyongyang': 'Korea Standard Time',
+ 'Asia/Qatar': 'Arab Standard Time',
+ 'Asia/Qyzylorda': 'Central Asia Standard Time',
+ 'Asia/Rangoon': 'Myanmar Standard Time',
+ 'Asia/Riyadh': 'Arab Standard Time',
+ 'Asia/Saigon': 'SE Asia Standard Time',
+ 'Asia/Sakhalin': 'Vladivostok Standard Time',
+ 'Asia/Samarkand': 'West Asia Standard Time',
+ 'Asia/Seoul': 'Korea Standard Time',
+ 'Asia/Shanghai': 'China Standard Time',
+ 'Asia/Singapore': 'Singapore Standard Time',
+ 'Asia/Taipei': 'Taipei Standard Time',
+ 'Asia/Tashkent': 'West Asia Standard Time',
+ 'Asia/Tbilisi': 'Georgian Standard Time',
+ 'Asia/Tehran': 'Iran Standard Time',
+ 'Asia/Thimphu': 'Bangladesh Standard Time',
+ 'Asia/Tokyo': 'Tokyo Standard Time',
+ 'Asia/Ulaanbaatar': 'Ulaanbaatar Standard Time',
+ 'Asia/Urumqi': 'China Standard Time',
+ 'Asia/Ust-Nera': 'Vladivostok Standard Time',
+ 'Asia/Vientiane': 'SE Asia Standard Time',
+ 'Asia/Vladivostok': 'Vladivostok Standard Time',
+ 'Asia/Yakutsk': 'Yakutsk Standard Time',
+ 'Asia/Yekaterinburg': 'Ekaterinburg Standard Time',
+ 'Asia/Yerevan': 'Caucasus Standard Time',
+ 'Atlantic/Azores': 'Azores Standard Time',
+ 'Atlantic/Bermuda': 'Atlantic Standard Time',
+ 'Atlantic/Canary': 'GMT Standard Time',
+ 'Atlantic/Cape_Verde': 'Cape Verde Standard Time',
+ 'Atlantic/Faeroe': 'GMT Standard Time',
+ 'Atlantic/Madeira': 'GMT Standard Time',
+ 'Atlantic/Reykjavik': 'Greenwich Standard Time',
+ 'Atlantic/South_Georgia': 'UTC-02',
+ 'Atlantic/St_Helena': 'Greenwich Standard Time',
+ 'Atlantic/Stanley': 'SA Eastern Standard Time',
+ 'Australia/Adelaide': 'Cen. Australia Standard Time',
+ 'Australia/Brisbane': 'E. Australia Standard Time',
+ 'Australia/Broken_Hill': 'Cen. Australia Standard Time',
+ 'Australia/Currie': 'Tasmania Standard Time',
+ 'Australia/Darwin': 'AUS Central Standard Time',
+ 'Australia/Hobart': 'Tasmania Standard Time',
+ 'Australia/Lindeman': 'E. Australia Standard Time',
+ 'Australia/Melbourne': 'AUS Eastern Standard Time',
+ 'Australia/Perth': 'W. Australia Standard Time',
+ 'Australia/Sydney': 'AUS Eastern Standard Time',
+ 'CST6CDT': 'Central Standard Time',
+ 'EST5EDT': 'Eastern Standard Time',
+ 'Etc/GMT': 'UTC',
+ 'Etc/GMT+1': 'Cape Verde Standard Time',
+ 'Etc/GMT+10': 'Hawaiian Standard Time',
+ 'Etc/GMT+11': 'UTC-11',
+ 'Etc/GMT+12': 'Dateline Standard Time',
+ 'Etc/GMT+2': 'UTC-02',
+ 'Etc/GMT+3': 'SA Eastern Standard Time',
+ 'Etc/GMT+4': 'SA Western Standard Time',
+ 'Etc/GMT+5': 'SA Pacific Standard Time',
+ 'Etc/GMT+6': 'Central America Standard Time',
+ 'Etc/GMT+7': 'US Mountain Standard Time',
+ 'Etc/GMT-1': 'W. Central Africa Standard Time',
+ 'Etc/GMT-10': 'West Pacific Standard Time',
+ 'Etc/GMT-11': 'Central Pacific Standard Time',
+ 'Etc/GMT-12': 'UTC+12',
+ 'Etc/GMT-13': 'Tonga Standard Time',
+ 'Etc/GMT-2': 'South Africa Standard Time',
+ 'Etc/GMT-3': 'E. Africa Standard Time',
+ 'Etc/GMT-4': 'Arabian Standard Time',
+ 'Etc/GMT-5': 'West Asia Standard Time',
+ 'Etc/GMT-6': 'Central Asia Standard Time',
+ 'Etc/GMT-7': 'SE Asia Standard Time',
+ 'Etc/GMT-8': 'Singapore Standard Time',
+ 'Etc/GMT-9': 'Tokyo Standard Time',
+ 'Etc/UTC': 'UTC',
+ 'Europe/Amsterdam': 'W. Europe Standard Time',
+ 'Europe/Andorra': 'W. Europe Standard Time',
+ 'Europe/Athens': 'GTB Standard Time',
+ 'Europe/Belgrade': 'Central Europe Standard Time',
+ 'Europe/Berlin': 'W. Europe Standard Time',
+ 'Europe/Bratislava': 'Central Europe Standard Time',
+ 'Europe/Brussels': 'Romance Standard Time',
+ 'Europe/Bucharest': 'GTB Standard Time',
+ 'Europe/Budapest': 'Central Europe Standard Time',
+ 'Europe/Busingen': 'W. Europe Standard Time',
+ 'Europe/Chisinau': 'GTB Standard Time',
+ 'Europe/Copenhagen': 'Romance Standard Time',
+ 'Europe/Dublin': 'GMT Standard Time',
+ 'Europe/Gibraltar': 'W. Europe Standard Time',
+ 'Europe/Guernsey': 'GMT Standard Time',
+ 'Europe/Helsinki': 'FLE Standard Time',
+ 'Europe/Isle_of_Man': 'GMT Standard Time',
+ 'Europe/Istanbul': 'Turkey Standard Time',
+ 'Europe/Jersey': 'GMT Standard Time',
+ 'Europe/Kaliningrad': 'Kaliningrad Standard Time',
+ 'Europe/Kiev': 'FLE Standard Time',
+ 'Europe/Lisbon': 'GMT Standard Time',
+ 'Europe/Ljubljana': 'Central Europe Standard Time',
+ 'Europe/London': 'GMT Standard Time',
+ 'Europe/Luxembourg': 'W. Europe Standard Time',
+ 'Europe/Madrid': 'Romance Standard Time',
+ 'Europe/Malta': 'W. Europe Standard Time',
+ 'Europe/Mariehamn': 'FLE Standard Time',
+ 'Europe/Minsk': 'Kaliningrad Standard Time',
+ 'Europe/Monaco': 'W. Europe Standard Time',
+ 'Europe/Moscow': 'Russian Standard Time',
+ 'Europe/Oslo': 'W. Europe Standard Time',
+ 'Europe/Paris': 'Romance Standard Time',
+ 'Europe/Podgorica': 'Central Europe Standard Time',
+ 'Europe/Prague': 'Central Europe Standard Time',
+ 'Europe/Riga': 'FLE Standard Time',
+ 'Europe/Rome': 'W. Europe Standard Time',
+ 'Europe/Samara': 'Russian Standard Time',
+ 'Europe/San_Marino': 'W. Europe Standard Time',
+ 'Europe/Sarajevo': 'Central European Standard Time',
+ 'Europe/Simferopol': 'FLE Standard Time',
+ 'Europe/Skopje': 'Central European Standard Time',
+ 'Europe/Sofia': 'FLE Standard Time',
+ 'Europe/Stockholm': 'W. Europe Standard Time',
+ 'Europe/Tallinn': 'FLE Standard Time',
+ 'Europe/Tirane': 'Central Europe Standard Time',
+ 'Europe/Uzhgorod': 'FLE Standard Time',
+ 'Europe/Vaduz': 'W. Europe Standard Time',
+ 'Europe/Vatican': 'W. Europe Standard Time',
+ 'Europe/Vienna': 'W. Europe Standard Time',
+ 'Europe/Vilnius': 'FLE Standard Time',
+ 'Europe/Volgograd': 'Russian Standard Time',
+ 'Europe/Warsaw': 'Central European Standard Time',
+ 'Europe/Zagreb': 'Central European Standard Time',
+ 'Europe/Zaporozhye': 'FLE Standard Time',
+ 'Europe/Zurich': 'W. Europe Standard Time',
+ 'Indian/Antananarivo': 'E. Africa Standard Time',
+ 'Indian/Chagos': 'Central Asia Standard Time',
+ 'Indian/Christmas': 'SE Asia Standard Time',
+ 'Indian/Cocos': 'Myanmar Standard Time',
+ 'Indian/Comoro': 'E. Africa Standard Time',
+ 'Indian/Kerguelen': 'West Asia Standard Time',
+ 'Indian/Mahe': 'Mauritius Standard Time',
+ 'Indian/Maldives': 'West Asia Standard Time',
+ 'Indian/Mauritius': 'Mauritius Standard Time',
+ 'Indian/Mayotte': 'E. Africa Standard Time',
+ 'Indian/Reunion': 'Mauritius Standard Time',
+ 'MST7MDT': 'Mountain Standard Time',
+ 'PST8PDT': 'Pacific Standard Time',
+ 'Pacific/Apia': 'Samoa Standard Time',
+ 'Pacific/Auckland': 'New Zealand Standard Time',
+ 'Pacific/Efate': 'Central Pacific Standard Time',
+ 'Pacific/Enderbury': 'Tonga Standard Time',
+ 'Pacific/Fakaofo': 'Tonga Standard Time',
+ 'Pacific/Fiji': 'Fiji Standard Time',
+ 'Pacific/Funafuti': 'UTC+12',
+ 'Pacific/Galapagos': 'Central America Standard Time',
+ 'Pacific/Guadalcanal': 'Central Pacific Standard Time',
+ 'Pacific/Guam': 'West Pacific Standard Time',
+ 'Pacific/Honolulu': 'Hawaiian Standard Time',
+ 'Pacific/Johnston': 'Hawaiian Standard Time',
+ 'Pacific/Kosrae': 'Central Pacific Standard Time',
+ 'Pacific/Kwajalein': 'UTC+12',
+ 'Pacific/Majuro': 'UTC+12',
+ 'Pacific/Midway': 'UTC-11',
+ 'Pacific/Nauru': 'UTC+12',
+ 'Pacific/Niue': 'UTC-11',
+ 'Pacific/Noumea': 'Central Pacific Standard Time',
+ 'Pacific/Pago_Pago': 'UTC-11',
+ 'Pacific/Palau': 'Tokyo Standard Time',
+ 'Pacific/Ponape': 'Central Pacific Standard Time',
+ 'Pacific/Port_Moresby': 'West Pacific Standard Time',
+ 'Pacific/Rarotonga': 'Hawaiian Standard Time',
+ 'Pacific/Saipan': 'West Pacific Standard Time',
+ 'Pacific/Tahiti': 'Hawaiian Standard Time',
+ 'Pacific/Tarawa': 'UTC+12',
+ 'Pacific/Tongatapu': 'Tonga Standard Time',
+ 'Pacific/Truk': 'West Pacific Standard Time',
+ 'Pacific/Wake': 'UTC+12',
+ 'Pacific/Wallis': 'UTC+12'
+}
diff --git a/nikola/plugin_categories.py b/nikola/plugin_categories.py
index 516df92..4109f2d 100644
--- a/nikola/plugin_categories.py
+++ b/nikola/plugin_categories.py
@@ -25,12 +25,15 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import absolute_import
+import sys
+import os
__all__ = [
'Command',
'LateTask',
'PageCompiler',
'RestExtension',
+ 'MarkdownExtension',
'Task',
'TaskMultiplier',
'TemplateSystem',
@@ -42,12 +45,6 @@ from doit.cmd_base import Command as DoitCommand
from .utils import LOGGER, first_line
-try:
- # ordereddict does not exist in py2.6
- from collections import OrderedDict
-except ImportError:
- OrderedDict = None # NOQA
-
class BasePlugin(IPlugin):
"""Base plugin class."""
@@ -55,6 +52,28 @@ class BasePlugin(IPlugin):
def set_site(self, site):
"""Sets site, which is a Nikola instance."""
self.site = site
+ self.inject_templates()
+
+ def inject_templates(self):
+ """If this plugin contains a 'templates' folder,
+ then templates/mako or templates/jinja will be inserted very early in
+ the theme chain."""
+
+ try:
+ # Sorry, found no other way to get this
+ mod_path = sys.modules[self.__class__.__module__].__file__
+ mod_dir = os.path.dirname(mod_path)
+ tmpl_dir = os.path.join(
+ mod_dir, 'templates', self.site.template_system.name
+ )
+ if os.path.isdir(tmpl_dir):
+ # Inject tmpl_dir low in the theme chain
+ self.site.template_system.inject_directory(tmpl_dir)
+ except AttributeError:
+ # In some cases, __builtin__ becomes the module of a plugin.
+ # We couldn’t reproduce that, and really find the reason for this,
+ # so let’s just ignore it and be done with it.
+ pass
class Command(BasePlugin, DoitCommand):
@@ -135,6 +154,8 @@ class BaseTask(BasePlugin):
class Task(BaseTask):
"""Plugins of this type are task generators."""
+ name = "dummy_task"
+
class LateTask(BaseTask):
"""Plugins of this type are executed after all plugins of type Task."""
@@ -145,16 +166,12 @@ class LateTask(BaseTask):
class TemplateSystem(BasePlugin):
"""Plugins of this type wrap templating systems."""
- name = "dummy templates"
+ name = "dummy_templates"
def set_directories(self, directories, cache_folder):
"""Sets the list of folders where templates are located and cache."""
raise NotImplementedError()
- def set_site(self, site):
- """Sets the site."""
- self.site = site
-
def template_deps(self, template_name):
"""Returns filenames which are dependencies for a template."""
raise NotImplementedError()
@@ -168,8 +185,12 @@ class TemplateSystem(BasePlugin):
raise NotImplementedError()
def render_template_to_string(self, template, context):
- """ Renders template to a string using context. """
+ """Renders template to a string using context. """
+ raise NotImplementedError()
+ def inject_directory(self, directory):
+ """Injects the directory with the lowest priority in the
+ template search mechanism."""
raise NotImplementedError()
@@ -189,27 +210,24 @@ class PageCompiler(BasePlugin):
name = "dummy compiler"
demote_headers = False
- if OrderedDict is not None:
- default_metadata = OrderedDict()
- else:
- # Graceful fallback. We could use a backport, but it is
- # not going to change anything, other than a bit uglier
- # and nonsensical layout. Not enough to care.
- default_metadata = {}
-
- default_metadata['title'] = ''
- default_metadata['slug'] = ''
- default_metadata['date'] = ''
- default_metadata['tags'] = ''
- default_metadata['link'] = ''
- default_metadata['description'] = ''
- default_metadata['type'] = 'text'
+ supports_onefile = True
+ default_metadata = {}
+
+ default_metadata = {
+ 'title': '',
+ 'slug': '',
+ 'date': '',
+ 'tags': '',
+ 'link': '',
+ 'description': '',
+ 'type': 'text',
+ }
def compile_html(self, source, dest, is_two_file=False):
"""Compile the source, save it on dest."""
raise NotImplementedError()
- def create_post(self, path, onefile=False, **kw):
+ def create_post(self, path, content=None, onefile=False, is_page=False, **kw):
"""Create post file with optional metadata."""
raise NotImplementedError()
@@ -222,6 +240,10 @@ class RestExtension(BasePlugin):
name = "dummy_rest_extension"
+class MarkdownExtension(BasePlugin):
+ name = "dummy_markdown_extension"
+
+
class SignalHandler(BasePlugin):
name = "dummy_signal_handler"
diff --git a/nikola/plugins/basic_import.py b/nikola/plugins/basic_import.py
index 27c0eb4..7b23f9c 100644
--- a/nikola/plugins/basic_import.py
+++ b/nikola/plugins/basic_import.py
@@ -29,6 +29,7 @@ import codecs
import csv
import datetime
import os
+from pkg_resources import resource_filename
try:
from urlparse import urlparse
@@ -89,13 +90,13 @@ class ImportMixin(object):
def generate_base_site(self):
if not os.path.exists(self.output_folder):
- os.system('nikola init ' + self.output_folder)
+ os.system('nikola init -q ' + self.output_folder)
else:
self.import_into_existing_site = True
utils.LOGGER.notice('The folder {0} already exists - assuming that this is a '
'already existing Nikola site.'.format(self.output_folder))
- filename = os.path.join(os.path.dirname(utils.__file__), 'conf.py.in')
+ filename = resource_filename('nikola', 'conf.py.in')
# The 'strict_undefined=True' will give the missing symbol name if any,
# (ex: NameError: 'THEME' is not defined )
# for other errors from mako/runtime.py, you can add format_extensions=True ,
diff --git a/nikola/plugins/command/auto.py b/nikola/plugins/command/auto.py
index d707d53..c46e0a3 100644
--- a/nikola/plugins/command/auto.py
+++ b/nikola/plugins/command/auto.py
@@ -73,11 +73,11 @@ class CommandAuto(Command):
server.watch('conf.py', 'nikola build')
server.watch('themes/', 'nikola build')
server.watch('templates/', 'nikola build')
- server.watch(self.site.config['GALLERY_PATH'])
+ server.watch(self.site.config['GALLERY_PATH'], 'nikola build')
for item in self.site.config['post_pages']:
server.watch(os.path.dirname(item[0]), 'nikola build')
for item in self.site.config['FILES_FOLDERS']:
- server.watch(os.path.dirname(item), 'nikola build')
+ server.watch(item, 'nikola build')
out_folder = self.site.config['OUTPUT_FOLDER']
if options and options.get('browser'):
diff --git a/nikola/plugins/command/bootswatch_theme.py b/nikola/plugins/command/bootswatch_theme.py
index 82c47d2..871a5ce 100644
--- a/nikola/plugins/command/bootswatch_theme.py
+++ b/nikola/plugins/command/bootswatch_theme.py
@@ -92,7 +92,10 @@ class CommandBootswatchTheme(Command):
LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent))
utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
for fname in ('bootstrap.min.css', 'bootstrap.css'):
- url = '/'.join(('http://bootswatch.com', version, swatch, fname))
+ url = 'http://bootswatch.com'
+ if version:
+ url += '/' + version
+ url = '/'.join((url, swatch, fname))
LOGGER.info("Downloading: " + url)
data = requests.get(url).text
with open(os.path.join('themes', name, 'assets', 'css', fname),
diff --git a/nikola/plugins/command/check.py b/nikola/plugins/command/check.py
index 26db321..76571a0 100644
--- a/nikola/plugins/command/check.py
+++ b/nikola/plugins/command/check.py
@@ -51,7 +51,7 @@ def real_scan_files(site):
fname = task.split(':', 1)[-1]
task_fnames.add(fname)
# And now check that there are no non-target files
- for root, dirs, files in os.walk(output_folder):
+ for root, dirs, files in os.walk(output_folder, followlinks=True):
for src_name in files:
fname = os.path.join(root, src_name)
real_fnames.add(fname)
@@ -139,6 +139,8 @@ class CommandCheck(Command):
rv = False
self.whitelist = [re.compile(x) for x in self.site.config['LINK_CHECK_WHITELIST']]
base_url = urlparse(self.site.config['BASE_URL'])
+ self.existing_targets.add(self.site.config['SITE_URL'])
+ self.existing_targets.add(self.site.config['BASE_URL'])
url_type = self.site.config['URL_TYPE']
try:
filename = task.split(":")[-1]
@@ -166,11 +168,15 @@ class CommandCheck(Command):
elif url_type in ('full_path', 'absolute'):
target_filename = os.path.abspath(
os.path.join(os.path.dirname(filename), parsed.path))
- if parsed.path.endswith('/'): # abspath removes trailing slashes
+ if parsed.path in ['', '/']:
+ target_filename = os.path.join(self.site.config['OUTPUT_FOLDER'], self.site.config['INDEX_FILE'])
+ elif parsed.path.endswith('/'): # abspath removes trailing slashes
target_filename += '/{0}'.format(self.site.config['INDEX_FILE'])
if target_filename.startswith(base_url.path):
target_filename = target_filename[len(base_url.path):]
target_filename = os.path.join(self.site.config['OUTPUT_FOLDER'], target_filename)
+ if parsed.path in ['', '/']:
+ target_filename = os.path.join(self.site.config['OUTPUT_FOLDER'], self.site.config['INDEX_FILE'])
if any(re.match(x, target_filename) for x in self.whitelist):
continue
@@ -233,7 +239,7 @@ class CommandCheck(Command):
return failure
def clean_files(self):
- only_on_output, _ = self.real_scan_files()
+ only_on_output, _ = real_scan_files(self.site)
for f in only_on_output:
os.unlink(f)
return True
diff --git a/nikola/plugins/command/console.py b/nikola/plugins/command/console.py
index b0a8958..9dfc975 100644
--- a/nikola/plugins/command/console.py
+++ b/nikola/plugins/command/console.py
@@ -30,7 +30,7 @@ import os
from nikola import __version__
from nikola.plugin_categories import Command
-from nikola.utils import get_logger, STDERR_HANDLER
+from nikola.utils import get_logger, STDERR_HANDLER, req_missing
LOGGER = get_logger('console', STDERR_HANDLER)
@@ -41,86 +41,102 @@ class CommandConsole(Command):
shells = ['ipython', 'bpython', 'plain']
doc_purpose = "start an interactive Python console with access to your site"
doc_description = """\
-Order of resolution: IPython → bpython [deprecated] → plain Python interpreter
-The site engine is accessible as `SITE`, and the config as `conf`."""
- header = "Nikola v" + __version__ + " -- {0} Console (conf = configuration, SITE = site engine)"
+The site engine is accessible as `site`, the config file as `conf`, and commands are available as `commands`.
+If there is no console to use specified (as -b, -i, -p) it tries IPython, then falls back to bpython, and finally falls back to the plain Python console."""
+ header = "Nikola v" + __version__ + " -- {0} Console (conf = configuration file, site = site engine, commands = nikola commands)"
cmd_options = [
{
+ 'name': 'bpython',
+ 'short': 'b',
+ 'long': 'bpython',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Use bpython',
+ },
+ {
+ 'name': 'ipython',
+ 'short': 'i',
+ 'long': 'plain',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Use IPython',
+ },
+ {
'name': 'plain',
'short': 'p',
'long': 'plain',
'type': bool,
'default': False,
- 'help': 'Force the plain Python console',
- }
+ 'help': 'Use the plain Python interpreter',
+ },
]
- def ipython(self):
+ def ipython(self, willful=True):
"""IPython shell."""
- from nikola import Nikola
try:
- import conf
- except ImportError:
- LOGGER.error("No configuration found, cannot run the console.")
- else:
import IPython
- SITE = Nikola(**conf.__dict__)
- SITE.scan_posts()
+ except ImportError as e:
+ if willful:
+ req_missing(['IPython'], 'use the IPython console')
+ raise e # That’s how _execute knows whether to try something else.
+ else:
+ site = self.context['site'] # NOQA
+ conf = self.context['conf'] # NOQA
+ commands = self.context['commands'] # NOQA
IPython.embed(header=self.header.format('IPython'))
- def bpython(self):
+ def bpython(self, willful=True):
"""bpython shell."""
- from nikola import Nikola
try:
- import conf
- except ImportError:
- LOGGER.error("No configuration found, cannot run the console.")
- else:
import bpython
- SITE = Nikola(**conf.__dict__)
- SITE.scan_posts()
- gl = {'conf': conf, 'SITE': SITE, 'Nikola': Nikola}
- bpython.embed(banner=self.header.format(
- 'bpython (Slightly Deprecated)'), locals_=gl)
+ except ImportError as e:
+ if willful:
+ req_missing(['bpython'], 'use the bpython console')
+ raise e # That’s how _execute knows whether to try something else.
+ else:
+ bpython.embed(banner=self.header.format('bpython'), locals_=self.context)
- def plain(self):
+ def plain(self, willful=True):
"""Plain Python shell."""
- from nikola import Nikola
+ import code
try:
- import conf
- SITE = Nikola(**conf.__dict__)
- SITE.scan_posts()
- gl = {'conf': conf, 'SITE': SITE, 'Nikola': Nikola}
+ import readline
except ImportError:
- LOGGER.error("No configuration found, cannot run the console.")
+ pass
else:
- import code
+ import rlcompleter
+ readline.set_completer(rlcompleter.Completer(self.context).complete)
+ readline.parse_and_bind("tab:complete")
+
+ pythonrc = os.environ.get("PYTHONSTARTUP")
+ if pythonrc and os.path.isfile(pythonrc):
try:
- import readline
- except ImportError:
+ execfile(pythonrc) # NOQA
+ except NameError:
pass
- else:
- import rlcompleter
- readline.set_completer(rlcompleter.Completer(gl).complete)
- readline.parse_and_bind("tab:complete")
- pythonrc = os.environ.get("PYTHONSTARTUP")
- if pythonrc and os.path.isfile(pythonrc):
- try:
- execfile(pythonrc) # NOQA
- except NameError:
- pass
-
- code.interact(local=gl, banner=self.header.format('Python'))
+ code.interact(local=self.context, banner=self.header.format('Python'))
def _execute(self, options, args):
"""Start the console."""
- if options['plain']:
- self.plain()
+ self.site.scan_posts()
+ # Create nice object with all commands:
+
+ self.context = {
+ 'conf': self.site.config,
+ 'site': self.site,
+ 'commands': self.site.commands,
+ }
+ if options['bpython']:
+ self.bpython(True)
+ elif options['ipython']:
+ self.ipython(True)
+ elif options['plain']:
+ self.plain(True)
else:
for shell in self.shells:
try:
- return getattr(self, shell)()
+ return getattr(self, shell)(False)
except ImportError:
pass
raise ImportError
diff --git a/nikola/plugins/command/deploy.py b/nikola/plugins/command/deploy.py
index bd1c15f..1bec1d3 100644
--- a/nikola/plugins/command/deploy.py
+++ b/nikola/plugins/command/deploy.py
@@ -31,7 +31,6 @@ import os
import sys
import subprocess
import time
-import pytz
from blinker import signal
@@ -62,10 +61,10 @@ class CommandDeploy(Command):
deploy_drafts = self.site.config.get('DEPLOY_DRAFTS', True)
deploy_future = self.site.config.get('DEPLOY_FUTURE', False)
+ undeployed_posts = []
if not (deploy_drafts and deploy_future):
# Remove drafts and future posts
out_dir = self.site.config['OUTPUT_FOLDER']
- undeployed_posts = []
self.site.scan_posts()
for post in self.site.timeline:
if (not deploy_drafts and post.is_draft) or \
@@ -114,9 +113,6 @@ class CommandDeploy(Command):
"""
- if undeployed is None:
- undeployed = []
-
event = {
'last_deploy': last_deploy,
'new_deploy': new_deploy,
@@ -124,11 +120,9 @@ class CommandDeploy(Command):
'undeployed': undeployed
}
- tzinfo = pytz.timezone(self.site.config['TIMEZONE'])
-
deployed = [
entry for entry in self.site.timeline
- if entry.date > (last_deploy.replace(tzinfo=tzinfo) if tzinfo else last_deploy) and entry not in undeployed
+ if entry.date > last_deploy.replace(tzinfo=self.site.tzinfo) and entry not in undeployed
]
event['deployed'] = deployed
diff --git a/nikola/plugins/command/github_deploy.plugin b/nikola/plugins/command/github_deploy.plugin
new file mode 100644
index 0000000..4cbc422
--- /dev/null
+++ b/nikola/plugins/command/github_deploy.plugin
@@ -0,0 +1,9 @@
+[Core]
+Name = github_deploy
+Module = github_deploy
+
+[Documentation]
+Author = Puneeth Chaganti
+Version = 0.1
+Website = http://getnikola.com
+Description = Deploy the site to GitHub pages.
diff --git a/nikola/plugins/command/github_deploy.py b/nikola/plugins/command/github_deploy.py
new file mode 100644
index 0000000..d4dd8c5
--- /dev/null
+++ b/nikola/plugins/command/github_deploy.py
@@ -0,0 +1,271 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2014 Puneeth Chaganti and others.
+
+# Permission is hereby granted, free of charge, to any
+# person obtaining a copy of this software and associated
+# documentation files (the "Software"), to deal in the
+# Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the
+# Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice
+# shall be included in all copies or substantial portions of
+# the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+from __future__ import print_function
+import os
+import shutil
+import subprocess
+import sys
+from textwrap import dedent
+
+from nikola.plugin_categories import Command
+from nikola.plugins.command.check import real_scan_files
+from nikola.utils import ask_yesno, get_logger
+from nikola.__main__ import main
+from nikola import __version__
+
+
+def uni_check_output(*args, **kwargs):
+ o = subprocess.check_output(*args, **kwargs)
+ return o.decode('utf-8')
+
+
+class CommandGitHubDeploy(Command):
+ """ Deploy site to GitHub pages. """
+ name = 'github_deploy'
+
+ doc_usage = ''
+ doc_purpose = 'deploy the site to GitHub pages'
+ doc_description = dedent(
+ """\
+ This command can be used to deploy your site to GitHub pages.
+ It performs the following actions:
+
+ 1. Ensure that your site is a git repository, and git is on the PATH.
+ 2. Ensure that the output directory is not committed on the
+ source branch.
+ 3. Check for changes, and prompt the user to continue, if required.
+ 4. Build the site
+ 5. Clean any files that are "unknown" to Nikola.
+ 6. Create a deploy branch, if one doesn't exist.
+ 7. Commit the output to this branch. (NOTE: Any untracked source
+ files, may get committed at this stage, on the wrong branch!)
+ 8. Push and deploy!
+
+ NOTE: This command needs your site to be a git repository, with a
+ master branch (or a different branch, configured using
+ GITHUB_SOURCE_BRANCH if you are pushing to user.github
+ .io/organization.github.io pages) containing the sources of your
+ site. You also, obviously, need to have `git` on your PATH,
+ and should be able to push to the repository specified as the remote
+ (origin, by default).
+ """
+ )
+
+ logger = None
+
+ _deploy_branch = ''
+ _source_branch = ''
+ _remote_name = ''
+
+ def _execute(self, command, args):
+
+ self.logger = get_logger(
+ CommandGitHubDeploy.name, self.site.loghandlers
+ )
+ self._source_branch = self.site.config.get(
+ 'GITHUB_SOURCE_BRANCH', 'master'
+ )
+ self._deploy_branch = self.site.config.get(
+ 'GITHUB_DEPLOY_BRANCH', 'gh-pages'
+ )
+ self._remote_name = self.site.config.get(
+ 'GITHUB_REMOTE_NAME', 'origin'
+ )
+
+ self._ensure_git_repo()
+
+ self._exit_if_output_committed()
+
+ if not self._prompt_continue():
+ return
+
+ build = main(['build'])
+ if build != 0:
+ self.logger.error('Build failed, not deploying to GitHub')
+ sys.exit(build)
+
+ only_on_output, _ = real_scan_files(self.site)
+ for f in only_on_output:
+ os.unlink(f)
+
+ self._checkout_deploy_branch()
+
+ self._copy_output()
+
+ self._commit_and_push()
+
+ return
+
+ def _commit_and_push(self):
+ """ Commit all the files and push. """
+
+ deploy = self._deploy_branch
+ source = self._source_branch
+ remote = self._remote_name
+
+ source_commit = uni_check_output(['git', 'rev-parse', source])
+ commit_message = (
+ 'Nikola auto commit.\n\n'
+ 'Source commit: %s'
+ 'Nikola version: %s' % (source_commit, __version__)
+ )
+
+ commands = [
+ ['git', 'add', '-A'],
+ ['git', 'commit', '-m', commit_message],
+ ['git', 'push', '-f', remote, '%s:%s' % (deploy, deploy)],
+ ['git', 'checkout', source],
+ ]
+
+ for command in commands:
+ self.logger.info("==> {0}".format(command))
+ try:
+ subprocess.check_call(command)
+ except subprocess.CalledProcessError as e:
+ self.logger.error(
+ 'Failed GitHub deployment — command {0} '
+ 'returned {1}'.format(e.cmd, e.returncode)
+ )
+ sys.exit(e.returncode)
+
+ def _copy_output(self):
+ """ Copy all output to the top level directory. """
+ output_folder = self.site.config['OUTPUT_FOLDER']
+ for each in os.listdir(output_folder):
+ if os.path.exists(each):
+ if os.path.isdir(each):
+ shutil.rmtree(each)
+
+ else:
+ os.unlink(each)
+
+ shutil.move(os.path.join(output_folder, each), '.')
+
+ def _checkout_deploy_branch(self):
+ """ Check out the deploy branch
+
+ Creates an orphan branch if not present.
+
+ """
+
+ deploy = self._deploy_branch
+
+ try:
+ subprocess.check_call(
+ [
+ 'git', 'show-ref', '--verify', '--quiet',
+ 'refs/heads/%s' % deploy
+ ]
+ )
+ except subprocess.CalledProcessError:
+ self._create_orphan_deploy_branch()
+ else:
+ subprocess.check_call(['git', 'checkout', deploy])
+
+ def _create_orphan_deploy_branch(self):
+ """ Create an orphan deploy branch """
+
+ result = subprocess.check_call(
+ ['git', 'checkout', '--orphan', self._deploy_branch]
+ )
+ if result != 0:
+ self.logger.error('Failed to create a deploy branch')
+ sys.exit(1)
+
+ result = subprocess.check_call(['git', 'rm', '-rf', '.'])
+ if result != 0:
+ self.logger.error('Failed to create a deploy branch')
+ sys.exit(1)
+
+ with open('.gitignore', 'w') as f:
+ f.write('%s\n' % self.site.config['OUTPUT_FOLDER'])
+ f.write('%s\n' % self.site.config['CACHE_FOLDER'])
+ f.write('*.pyc\n')
+ f.write('*.db\n')
+
+ subprocess.check_call(['git', 'add', '.gitignore'])
+ subprocess.check_call(['git', 'commit', '-m', 'Add .gitignore'])
+
+ def _ensure_git_repo(self):
+ """ Ensure that the site is a git-repo.
+
+ Also make sure that a remote with the specified name exists.
+
+ """
+
+ try:
+ remotes = uni_check_output(['git', 'remote'])
+ except subprocess.CalledProcessError as e:
+ self.logger.notice('github_deploy needs a git repository!')
+ sys.exit(e.returncode)
+ except OSError as e:
+ import errno
+ self.logger.error('Running git failed with {0}'.format(e))
+ if e.errno == errno.ENOENT:
+ self.logger.notice('Is git on the PATH?')
+ sys.exit(1)
+ else:
+ if self._remote_name not in remotes:
+ self.logger.error(
+ 'Need a remote called "%s" configured' % self._remote_name
+ )
+ sys.exit(1)
+
+ def _exit_if_output_committed(self):
+ """ Exit if the output folder is committed on the source branch. """
+
+ source = self._source_branch
+ subprocess.check_call(['git', 'checkout', source])
+
+ output_folder = self.site.config['OUTPUT_FOLDER']
+ output_log = uni_check_output(
+ ['git', 'ls-files', '--', output_folder]
+ )
+
+ if len(output_log.strip()) > 0:
+ self.logger.error(
+ 'Output folder is committed on the source branch. '
+ 'Cannot proceed until it is removed.'
+ )
+ sys.exit(1)
+
+ def _prompt_continue(self):
+ """ Show uncommitted changes, and ask if user wants to continue. """
+
+ changes = uni_check_output(['git', 'status', '--porcelain'])
+ if changes.strip():
+ changes = uni_check_output(['git', 'status']).strip()
+ message = (
+ "You have the following changes:\n%s\n\n"
+ "Anything not committed, and unknown to Nikola may be lost, "
+ "or committed onto the wrong branch. Do you wish to continue?"
+ ) % changes
+ proceed = ask_yesno(message, False)
+ else:
+ proceed = True
+
+ return proceed
diff --git a/nikola/plugins/command/import_blogger.plugin b/nikola/plugins/command/import_blogger.plugin
deleted file mode 100644
index 91a7cb6..0000000
--- a/nikola/plugins/command/import_blogger.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = import_blogger
-Module = import_blogger
-
-[Documentation]
-Author = Roberto Alsina
-Version = 0.2
-Website = http://getnikola.com
-Description = Import a blogger site from a XML dump.
-
diff --git a/nikola/plugins/command/import_blogger.py b/nikola/plugins/command/import_blogger.py
deleted file mode 100644
index dd629c4..0000000
--- a/nikola/plugins/command/import_blogger.py
+++ /dev/null
@@ -1,228 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-from __future__ import unicode_literals, print_function
-import datetime
-import os
-import time
-
-try:
- from urlparse import urlparse
-except ImportError:
- from urllib.parse import urlparse # NOQA
-
-try:
- import feedparser
-except ImportError:
- feedparser = None # NOQA
-
-from nikola.plugin_categories import Command
-from nikola import utils
-from nikola.utils import req_missing
-from nikola.plugins.basic_import import ImportMixin
-from nikola.plugins.command.init import SAMPLE_CONF, prepare_config
-
-LOGGER = utils.get_logger('import_blogger', utils.STDERR_HANDLER)
-
-
-class CommandImportBlogger(Command, ImportMixin):
- """Import a blogger dump."""
-
- name = "import_blogger"
- needs_config = False
- doc_usage = "[options] blogger_export_file"
- doc_purpose = "import a blogger dump"
- cmd_options = ImportMixin.cmd_options + [
- {
- 'name': 'exclude_drafts',
- 'long': 'no-drafts',
- 'short': 'd',
- 'default': False,
- 'type': bool,
- 'help': "Don't import drafts",
- },
- ]
-
- def _execute(self, options, args):
- """Import a Blogger blog from an export file into a Nikola site."""
- # Parse the data
- if feedparser is None:
- req_missing(['feedparser'], 'import Blogger dumps')
- return
-
- if not args:
- print(self.help())
- return
-
- options['filename'] = args[0]
- self.blogger_export_file = options['filename']
- self.output_folder = options['output_folder']
- self.import_into_existing_site = False
- self.exclude_drafts = options['exclude_drafts']
- self.url_map = {}
- channel = self.get_channel_from_file(self.blogger_export_file)
- self.context = self.populate_context(channel)
- conf_template = self.generate_base_site()
- self.context['REDIRECTIONS'] = self.configure_redirections(
- self.url_map)
-
- self.import_posts(channel)
- self.write_urlmap_csv(
- os.path.join(self.output_folder, 'url_map.csv'), self.url_map)
-
- conf_out_path = self.get_configuration_output_path()
- # if it tracebacks here, look a comment in
- # basic_import.Import_Mixin.generate_base_site
- conf_template_render = conf_template.render(**prepare_config(self.context))
- self.write_configuration(conf_out_path, conf_template_render)
-
- @classmethod
- def get_channel_from_file(cls, filename):
- if not os.path.isfile(filename):
- raise Exception("Missing file: %s" % filename)
- return feedparser.parse(filename)
-
- @staticmethod
- def populate_context(channel):
- context = SAMPLE_CONF.copy()
- context['DEFAULT_LANG'] = 'en' # blogger doesn't include the language
- # in the dump
- context['BLOG_TITLE'] = channel.feed.title
-
- context['BLOG_DESCRIPTION'] = '' # Missing in the dump
- context['SITE_URL'] = channel.feed.link
- context['BLOG_EMAIL'] = channel.feed.author_detail.email
- context['BLOG_AUTHOR'] = channel.feed.author_detail.name
- context['POSTS'] = '''(
- ("posts/*.txt", "posts", "post.tmpl"),
- ("posts/*.rst", "posts", "post.tmpl"),
- ("posts/*.html", "posts", "post.tmpl"),
- )'''
- context['PAGES'] = '''(
- ("articles/*.txt", "articles", "story.tmpl"),
- ("articles/*.rst", "articles", "story.tmpl"),
- )'''
- context['COMPILERS'] = '''{
- "rest": ('.txt', '.rst'),
- "markdown": ('.md', '.mdown', '.markdown', '.wp'),
- "html": ('.html', '.htm')
- }
- '''
-
- return context
-
- def import_item(self, item, out_folder=None):
- """Takes an item from the feed and creates a post file."""
- if out_folder is None:
- out_folder = 'posts'
-
- # link is something like http://foo.com/2012/09/01/hello-world/
- # So, take the path, utils.slugify it, and that's our slug
- link = item.link
- link_path = urlparse(link).path
-
- title = item.title
-
- # blogger supports empty titles, which Nikola doesn't
- if not title:
- LOGGER.warn("Empty title in post with URL {0}. Using NO_TITLE "
- "as placeholder, please fix.".format(link))
- title = "NO_TITLE"
-
- if link_path.lower().endswith('.html'):
- link_path = link_path[:-5]
-
- slug = utils.slugify(link_path)
-
- if not slug: # should never happen
- LOGGER.error("Error converting post:", title)
- return
-
- description = ''
- post_date = datetime.datetime.fromtimestamp(time.mktime(
- item.published_parsed))
-
- for candidate in item.content:
- if candidate.type == 'text/html':
- content = candidate.value
- break
- # FIXME: handle attachments
-
- tags = []
- for tag in item.tags:
- if tag.scheme == 'http://www.blogger.com/atom/ns#':
- tags.append(tag.term)
-
- if item.get('app_draft'):
- tags.append('draft')
- is_draft = True
- else:
- is_draft = False
-
- self.url_map[link] = self.context['SITE_URL'] + '/' + \
- out_folder + '/' + slug + '.html'
-
- if is_draft and self.exclude_drafts:
- LOGGER.notice('Draft "{0}" will not be imported.'.format(title))
- elif content.strip():
- # If no content is found, no files are written.
- content = self.transform_content(content)
-
- self.write_metadata(os.path.join(self.output_folder, out_folder,
- slug + '.meta'),
- title, slug, post_date, description, tags)
- self.write_content(
- os.path.join(self.output_folder, out_folder, slug + '.html'),
- content)
- else:
- LOGGER.warn('Not going to import "{0}" because it seems to contain'
- ' no content.'.format(title))
-
- def process_item(self, item):
- post_type = item.tags[0].term
-
- if post_type == 'http://schemas.google.com/blogger/2008/kind#post':
- self.import_item(item, 'posts')
- elif post_type == 'http://schemas.google.com/blogger/2008/kind#page':
- self.import_item(item, 'stories')
- elif post_type == ('http://schemas.google.com/blogger/2008/kind'
- '#settings'):
- # Ignore settings
- pass
- elif post_type == ('http://schemas.google.com/blogger/2008/kind'
- '#template'):
- # Ignore template
- pass
- elif post_type == ('http://schemas.google.com/blogger/2008/kind'
- '#comment'):
- # FIXME: not importing comments. Does blogger support "pages"?
- pass
- else:
- LOGGER.warn("Unknown post_type:", post_type)
-
- def import_posts(self, channel):
- for item in channel.entries:
- self.process_item(item)
diff --git a/nikola/plugins/command/import_feed.plugin b/nikola/plugins/command/import_feed.plugin
deleted file mode 100644
index 26e570a..0000000
--- a/nikola/plugins/command/import_feed.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = import_feed
-Module = import_feed
-
-[Documentation]
-Author = Grzegorz Śliwiński
-Version = 0.1
-Website = http://www.fizyk.net.pl/
-Description = Import a blog posts from a RSS/Atom dump
-
diff --git a/nikola/plugins/command/import_feed.py b/nikola/plugins/command/import_feed.py
deleted file mode 100644
index ee59277..0000000
--- a/nikola/plugins/command/import_feed.py
+++ /dev/null
@@ -1,200 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-from __future__ import unicode_literals, print_function
-import datetime
-import os
-import time
-
-try:
- from urlparse import urlparse
-except ImportError:
- from urllib.parse import urlparse # NOQA
-
-try:
- import feedparser
-except ImportError:
- feedparser = None # NOQA
-
-from nikola.plugin_categories import Command
-from nikola import utils
-from nikola.utils import req_missing
-from nikola.plugins.basic_import import ImportMixin
-from nikola.plugins.command.init import SAMPLE_CONF, prepare_config
-
-LOGGER = utils.get_logger('import_feed', utils.STDERR_HANDLER)
-
-
-class CommandImportFeed(Command, ImportMixin):
- """Import a feed dump."""
-
- name = "import_feed"
- needs_config = False
- doc_usage = "[options] feed_file"
- doc_purpose = "import a RSS/Atom dump"
- cmd_options = ImportMixin.cmd_options
-
- def _execute(self, options, args):
- '''
- Import Atom/RSS feed
- '''
- if feedparser is None:
- req_missing(['feedparser'], 'import feeds')
- return
-
- if not args:
- print(self.help())
- return
-
- options['filename'] = args[0]
- self.feed_export_file = options['filename']
- self.output_folder = options['output_folder']
- self.import_into_existing_site = False
- self.url_map = {}
- channel = self.get_channel_from_file(self.feed_export_file)
- self.context = self.populate_context(channel)
- conf_template = self.generate_base_site()
- self.context['REDIRECTIONS'] = self.configure_redirections(
- self.url_map)
-
- self.import_posts(channel)
-
- self.write_configuration(self.get_configuration_output_path(
- ), conf_template.render(**prepare_config(self.context)))
-
- @classmethod
- def get_channel_from_file(cls, filename):
- return feedparser.parse(filename)
-
- @staticmethod
- def populate_context(channel):
- context = SAMPLE_CONF.copy()
- context['DEFAULT_LANG'] = channel.feed.title_detail.language \
- if channel.feed.title_detail.language else 'en'
- context['BLOG_TITLE'] = channel.feed.title
-
- context['BLOG_DESCRIPTION'] = channel.feed.get('subtitle', '')
- context['SITE_URL'] = channel.feed.get('link', '').rstrip('/')
- context['BLOG_EMAIL'] = channel.feed.author_detail.get('email', '') if 'author_detail' in channel.feed else ''
- context['BLOG_AUTHOR'] = channel.feed.author_detail.get('name', '') if 'author_detail' in channel.feed else ''
-
- context['POSTS'] = '''(
- ("posts/*.html", "posts", "post.tmpl"),
- )'''
- context['PAGES'] = '''(
- ("stories/*.html", "stories", "story.tmpl"),
- )'''
- context['COMPILERS'] = '''{
- "rest": ('.txt', '.rst'),
- "markdown": ('.md', '.mdown', '.markdown', '.wp'),
- "html": ('.html', '.htm')
- }
- '''
-
- return context
-
- def import_posts(self, channel):
- for item in channel.entries:
- self.process_item(item)
-
- def process_item(self, item):
- self.import_item(item, 'posts')
-
- def import_item(self, item, out_folder=None):
- """Takes an item from the feed and creates a post file."""
- if out_folder is None:
- out_folder = 'posts'
-
- # link is something like http://foo.com/2012/09/01/hello-world/
- # So, take the path, utils.slugify it, and that's our slug
- link = item.link
- link_path = urlparse(link).path
-
- title = item.title
-
- # blogger supports empty titles, which Nikola doesn't
- if not title:
- LOGGER.warn("Empty title in post with URL {0}. Using NO_TITLE "
- "as placeholder, please fix.".format(link))
- title = "NO_TITLE"
-
- if link_path.lower().endswith('.html'):
- link_path = link_path[:-5]
-
- slug = utils.slugify(link_path)
-
- if not slug: # should never happen
- LOGGER.error("Error converting post:", title)
- return
-
- description = ''
- post_date = datetime.datetime.fromtimestamp(time.mktime(
- item.published_parsed))
- if item.get('content'):
- for candidate in item.get('content', []):
- content = candidate.value
- break
- # FIXME: handle attachments
- elif item.get('summary'):
- content = item.get('summary')
-
- tags = []
- for tag in item.get('tags', []):
- tags.append(tag.term)
-
- if item.get('app_draft'):
- tags.append('draft')
- is_draft = True
- else:
- is_draft = False
-
- self.url_map[link] = self.context['SITE_URL'] + '/' + \
- out_folder + '/' + slug + '.html'
-
- if is_draft and self.exclude_drafts:
- LOGGER.notice('Draft "{0}" will not be imported.'.format(title))
- elif content.strip():
- # If no content is found, no files are written.
- content = self.transform_content(content)
-
- self.write_metadata(os.path.join(self.output_folder, out_folder,
- slug + '.meta'),
- title, slug, post_date, description, tags)
- self.write_content(
- os.path.join(self.output_folder, out_folder, slug + '.html'),
- content)
- else:
- LOGGER.warn('Not going to import "{0}" because it seems to contain'
- ' no content.'.format(title))
-
- @staticmethod
- def write_metadata(filename, title, slug, post_date, description, tags):
- ImportMixin.write_metadata(filename,
- title,
- slug,
- post_date.strftime(r'%Y/%m/%d %H:%m:%S'),
- description,
- tags)
diff --git a/nikola/plugins/command/import_wordpress.py b/nikola/plugins/command/import_wordpress.py
index b567c77..8ddc8c7 100644
--- a/nikola/plugins/command/import_wordpress.py
+++ b/nikola/plugins/command/import_wordpress.py
@@ -51,7 +51,7 @@ from nikola import utils
from nikola.utils import req_missing
from nikola.plugins.basic_import import ImportMixin, links
from nikola.nikola import DEFAULT_TRANSLATIONS_PATTERN
-from nikola.plugins.command.init import SAMPLE_CONF, prepare_config
+from nikola.plugins.command.init import SAMPLE_CONF, prepare_config, format_default_translations_config
LOGGER = utils.get_logger('import_wordpress', utils.STDERR_HANDLER)
@@ -136,6 +136,9 @@ class CommandImportWordpress(Command, ImportMixin):
self.separate_qtranslate_content = options.get('separate_qtranslate_content')
self.translations_pattern = options.get('translations_pattern')
+ # A place holder where extra language (if detected) will be stored
+ self.extra_languages = set()
+
if not self.no_downloads:
def show_info_about_mising_module(modulename):
LOGGER.error(
@@ -164,6 +167,8 @@ class CommandImportWordpress(Command, ImportMixin):
self.import_posts(channel)
+ self.context['TRANSLATIONS'] = format_default_translations_config(
+ self.extra_languages)
self.context['REDIRECTIONS'] = self.configure_redirections(
self.url_map)
self.write_urlmap_csv(
@@ -326,7 +331,7 @@ class CommandImportWordpress(Command, ImportMixin):
size_key = b'sizes'
file_key = b'file'
- if not size_key in metadata:
+ if size_key not in metadata:
continue
for filename in [metadata[size_key][size][file_key] for size in metadata[size_key]]:
@@ -452,6 +457,7 @@ class CommandImportWordpress(Command, ImportMixin):
out_content_filename \
= utils.get_translation_candidate(self.context,
slug + ".wp", lang)
+ self.extra_languages.add(lang)
meta_slug = slug
else:
out_meta_filename = slug + '.meta'
diff --git a/nikola/plugins/command/init.py b/nikola/plugins/command/init.py
index d7eeed7..8fb15e0 100644
--- a/nikola/plugins/command/init.py
+++ b/nikola/plugins/command/init.py
@@ -24,19 +24,24 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-from __future__ import print_function
+from __future__ import print_function, unicode_literals
import os
import shutil
import codecs
import json
-
+import textwrap
+import datetime
+import unidecode
+import dateutil.tz
from mako.template import Template
+from pkg_resources import resource_filename
import nikola
-from nikola.nikola import DEFAULT_TRANSLATIONS_PATTERN
+from nikola.nikola import DEFAULT_TRANSLATIONS_PATTERN, DEFAULT_INDEX_READ_MORE_LINK, DEFAULT_RSS_READ_MORE_LINK, LEGAL_VALUES
from nikola.plugin_categories import Command
-from nikola.utils import get_logger, makedirs, STDERR_HANDLER
-from nikola.winutils import fix_git_symlinked
+from nikola.utils import ask, ask_yesno, get_logger, makedirs, STDERR_HANDLER, load_messages
+from nikola.packages.tzlocal import get_localzone
+
LOGGER = get_logger('init', STDERR_HANDLER)
@@ -47,39 +52,144 @@ SAMPLE_CONF = {
'BLOG_EMAIL': "joe@demo.site",
'BLOG_DESCRIPTION': "This is a demo site for Nikola.",
'DEFAULT_LANG': "en",
+ 'TRANSLATIONS': """{
+ DEFAULT_LANG: "",
+ # Example for another language:
+ # "es": "./es",
+}""",
'THEME': 'bootstrap3',
+ 'TIMEZONE': 'UTC',
'COMMENT_SYSTEM': 'disqus',
'COMMENT_SYSTEM_ID': 'nikolademo',
'TRANSLATIONS_PATTERN': DEFAULT_TRANSLATIONS_PATTERN,
+ 'INDEX_READ_MORE_LINK': DEFAULT_INDEX_READ_MORE_LINK,
+ 'RSS_READ_MORE_LINK': DEFAULT_RSS_READ_MORE_LINK,
'POSTS': """(
-("posts/*.rst", "posts", "post.tmpl"),
-("posts/*.txt", "posts", "post.tmpl"),
+ ("posts/*.rst", "posts", "post.tmpl"),
+ ("posts/*.txt", "posts", "post.tmpl"),
)""",
'PAGES': """(
-("stories/*.rst", "stories", "story.tmpl"),
-("stories/*.txt", "stories", "story.tmpl"),
+ ("stories/*.rst", "stories", "story.tmpl"),
+ ("stories/*.txt", "stories", "story.tmpl"),
)""",
'COMPILERS': """{
-"rest": ('.rst', '.txt'),
-"markdown": ('.md', '.mdown', '.markdown'),
-"textile": ('.textile',),
-"txt2tags": ('.t2t',),
-"bbcode": ('.bb',),
-"wiki": ('.wiki',),
-"ipynb": ('.ipynb',),
-"html": ('.html', '.htm'),
-# PHP files are rendered the usual way (i.e. with the full templates).
-# The resulting files have .php extensions, making it possible to run
-# them without reconfiguring your server to recognize them.
-"php": ('.php',),
-# Pandoc detects the input from the source filename
-# but is disabled by default as it would conflict
-# with many of the others.
-# "pandoc": ('.rst', '.md', '.txt'),
+ "rest": ('.rst', '.txt'),
+ "markdown": ('.md', '.mdown', '.markdown'),
+ "textile": ('.textile',),
+ "txt2tags": ('.t2t',),
+ "bbcode": ('.bb',),
+ "wiki": ('.wiki',),
+ "ipynb": ('.ipynb',),
+ "html": ('.html', '.htm'),
+ # PHP files are rendered the usual way (i.e. with the full templates).
+ # The resulting files have .php extensions, making it possible to run
+ # them without reconfiguring your server to recognize them.
+ "php": ('.php',),
+ # Pandoc detects the input from the source filename
+ # but is disabled by default as it would conflict
+ # with many of the others.
+ # "pandoc": ('.rst', '.md', '.txt'),
+}""",
+ 'NAVIGATION_LINKS': """{
+ DEFAULT_LANG: (
+ ("/archive.html", "Archives"),
+ ("/categories/index.html", "Tags"),
+ ("/rss.xml", "RSS feed"),
+ ),
}""",
'REDIRECTIONS': [],
}
+# Generate a list of supported languages here.
+# Ugly code follows.
+_suplang = {}
+_sllength = 0
+
+for k, v in LEGAL_VALUES['TRANSLATIONS'].items():
+ if not isinstance(k, tuple):
+ main = k
+ _suplang[main] = v
+ else:
+ main = k[0]
+ k = k[1:]
+ bad = []
+ good = []
+ for i in k:
+ if i.startswith('!'):
+ bad.append(i[1:])
+ else:
+ good.append(i)
+ different = ''
+ if good or bad:
+ different += ' ['
+ if good:
+ different += 'ALTERNATIVELY ' + ', '.join(good)
+ if bad:
+ if good:
+ different += '; '
+ different += 'NOT ' + ', '.join(bad)
+ if good or bad:
+ different += ']'
+ _suplang[main] = v + different
+
+ if len(main) > _sllength:
+ _sllength = len(main)
+
+_sllength = str(_sllength)
+suplang = (u'# {0:<' + _sllength + u'} {1}\n').format('en', 'English')
+del _suplang['en']
+for k, v in sorted(_suplang.items()):
+ suplang += (u'# {0:<' + _sllength + u'} {1}\n').format(k, v)
+
+SAMPLE_CONF['_SUPPORTED_LANGUAGES'] = suplang.strip()
+
+# Generate a list of supported comment systems here.
+
+SAMPLE_CONF['_SUPPORTED_COMMENT_SYSTEMS'] = '\n'.join(textwrap.wrap(
+ u', '.join(LEGAL_VALUES['COMMENT_SYSTEM']),
+ initial_indent=u'# ', subsequent_indent=u'# ', width=79))
+
+
+def format_default_translations_config(additional_languages):
+ """Return the string to configure the TRANSLATIONS config variable to
+ make each additional language visible on the generated site."""
+ if not additional_languages:
+ return SAMPLE_CONF["TRANSLATIONS"]
+ lang_paths = [' DEFAULT_LANG: "",']
+ for lang in sorted(additional_languages):
+ lang_paths.append(' "{0}": "./{0}",'.format(lang))
+ return "{{\n{0}\n}}".format("\n".join(lang_paths))
+
+
+def format_navigation_links(additional_languages, default_lang, messages):
+ """Return the string to configure NAVIGATION_LINKS."""
+ f = u"""\
+ {0}: (
+ ("{1}/archive.html", "{2[Archive]}"),
+ ("{1}/categories/index.html", "{2[Tags]}"),
+ ("{1}/rss.xml", "{2[RSS feed]}"),
+ ),"""
+
+ pairs = []
+
+ def get_msg(lang):
+ """Generate a smaller messages dict with fallback."""
+ fmsg = {}
+ for i in (u'Archive', u'Tags', u'RSS feed'):
+ if messages[lang][i]:
+ fmsg[i] = messages[lang][i]
+ else:
+ fmsg[i] = i
+ return fmsg
+
+ # handle the default language
+ pairs.append(f.format('DEFAULT_LANG', '', get_msg(default_lang)))
+
+ for l in additional_languages:
+ pairs.append(f.format(json.dumps(l), '/' + l, get_msg(l)))
+
+ return u'{{\n{0}\n}}'.format('\n\n'.join(pairs))
+
# In order to ensure proper escaping, all variables but the three
# pre-formatted ones are handled by json.dumps().
@@ -87,7 +197,10 @@ def prepare_config(config):
"""Parse sample config with JSON."""
p = config.copy()
p.update(dict((k, json.dumps(v)) for k, v in p.items()
- if k not in ('POSTS', 'PAGES', 'COMPILERS')))
+ if k not in ('POSTS', 'PAGES', 'COMPILERS', 'TRANSLATIONS', 'NAVIGATION_LINKS', '_SUPPORTED_LANGUAGES', '_SUPPORTED_COMMENT_SYSTEMS', 'INDEX_READ_MORE_LINK', 'RSS_READ_MORE_LINK')))
+ # READ_MORE_LINKs require some special treatment.
+ p['INDEX_READ_MORE_LINK'] = "'" + p['INDEX_READ_MORE_LINK'].replace("'", "\\'") + "'"
+ p['RSS_READ_MORE_LINK'] = "'" + p['RSS_READ_MORE_LINK'].replace("'", "\\'") + "'"
return p
@@ -97,13 +210,22 @@ class CommandInit(Command):
name = "init"
- doc_usage = "[--demo] folder"
+ doc_usage = "[--demo] [--quiet] folder"
needs_config = False
doc_purpose = "create a Nikola site in the specified folder"
cmd_options = [
{
+ 'name': 'quiet',
+ 'long': 'quiet',
+ 'short': 'q',
+ 'default': False,
+ 'type': bool,
+ 'help': "Do not ask questions about config.",
+ },
+ {
'name': 'demo',
'long': 'demo',
+ 'short': 'd',
'default': False,
'type': bool,
'help': "Create a site filled with example data.",
@@ -112,15 +234,12 @@ class CommandInit(Command):
@classmethod
def copy_sample_site(cls, target):
- lib_path = cls.get_path_to_nikola_modules()
- src = os.path.join(lib_path, 'data', 'samplesite')
+ src = resource_filename('nikola', os.path.join('data', 'samplesite'))
shutil.copytree(src, target)
- fix_git_symlinked(src, target)
@classmethod
def create_configuration(cls, target):
- lib_path = cls.get_path_to_nikola_modules()
- template_path = os.path.join(lib_path, 'conf.py.in')
+ template_path = resource_filename('nikola', 'conf.py.in')
conf_template = Template(filename=template_path)
conf_path = os.path.join(target, 'conf.py')
with codecs.open(conf_path, 'w+', 'utf8') as fd:
@@ -132,16 +251,167 @@ class CommandInit(Command):
makedirs(os.path.join(target, folder))
@staticmethod
- def get_path_to_nikola_modules():
- return os.path.dirname(nikola.__file__)
+ def ask_questions(target):
+ """Ask some questions about Nikola."""
+ def lhandler(default, toconf, show_header=True):
+ if show_header:
+ print("We will now ask you to provide the list of languages you want to use.")
+ print("Please list all the desired languages, comma-separated, using ISO 639-1 codes. The first language will be used as the default.")
+ print("Type '?' (a question mark, sans quotes) to list available languages.")
+ answer = ask('Language(s) to use', 'en')
+ while answer.strip() == '?':
+ print('\n# Available languages:')
+ try:
+ print(SAMPLE_CONF['_SUPPORTED_LANGUAGES'] + '\n')
+ except UnicodeEncodeError:
+ # avoid Unicode characters in supported language names
+ print(unidecode.unidecode(SAMPLE_CONF['_SUPPORTED_LANGUAGES']) + '\n')
+ answer = ask('Language(s) to use', 'en')
+
+ langs = [i.strip().lower().replace('-', '_') for i in answer.split(',')]
+ for partial, full in LEGAL_VALUES['_TRANSLATIONS_WITH_COUNTRY_SPECIFIERS'].items():
+ if partial in langs:
+ langs[langs.index(partial)] = full
+ print("NOTICE: Assuming '{0}' instead of '{1}'.".format(full, partial))
+
+ default = langs.pop(0)
+ SAMPLE_CONF['DEFAULT_LANG'] = default
+ # format_default_translations_config() is intelligent enough to
+ # return the current value if there are no additional languages.
+ SAMPLE_CONF['TRANSLATIONS'] = format_default_translations_config(langs)
+
+ # Get messages for navigation_links. In order to do this, we need
+ # to generate a throwaway TRANSLATIONS dict.
+ tr = {default: ''}
+ for l in langs:
+ tr[l] = './' + l
+ # Assuming that base contains all the locales, and that base does
+ # not inherit from anywhere.
+ try:
+ messages = load_messages(['base'], tr, default)
+ SAMPLE_CONF['NAVIGATION_LINKS'] = format_navigation_links(langs, default, messages)
+ except nikola.utils.LanguageNotFoundError as e:
+ print(" ERROR: the language '{0}' is not supported.".format(e.lang))
+ print(" Are you sure you spelled the name correctly? Names are case-sensitive and need to be reproduced as-is (complete with the country specifier, if any).")
+ print("\nType '?' (a question mark, sans quotes) to list available languages.")
+ lhandler(default, toconf, show_header=False)
+
+ def tzhandler(default, toconf):
+ print("\nPlease choose the correct time zone for your blog. Nikola uses the tz database.")
+ print("You can find your time zone here:")
+ print("http://en.wikipedia.org/wiki/List_of_tz_database_time_zones")
+ print("")
+ answered = False
+ while not answered:
+ try:
+ lz = get_localzone()
+ except:
+ lz = None
+ answer = ask('Time zone', lz if lz else "UTC")
+ tz = dateutil.tz.gettz(answer)
+ if tz is not None:
+ time = datetime.datetime.now(tz).strftime('%H:%M:%S')
+ print(" Current time in {0}: {1}".format(answer, time))
+ answered = ask_yesno("Use this time zone?", True)
+ else:
+ print(" ERROR: Time zone not found. Please try again. Time zones are case-sensitive.")
+
+ SAMPLE_CONF['TIMEZONE'] = answer
+
+ def chandler(default, toconf):
+ print("You can configure comments now. Type '?' (a question mark, sans quotes) to list available comment systems. If you do not want any comments, just leave the field blank.")
+ answer = ask('Comment system', '')
+ while answer.strip() == '?':
+ print('\n# Available comment systems:')
+ print(SAMPLE_CONF['_SUPPORTED_COMMENT_SYSTEMS'])
+ print('')
+ answer = ask('Comment system', '')
+
+ while answer and answer not in LEGAL_VALUES['COMMENT_SYSTEM']:
+ if answer != '?':
+ print(' ERROR: Nikola does not know this comment system.')
+ print('\n# Available comment systems:')
+ print(SAMPLE_CONF['_SUPPORTED_COMMENT_SYSTEMS'])
+ print('')
+ answer = ask('Comment system', '')
+
+ SAMPLE_CONF['COMMENT_SYSTEM'] = answer
+ SAMPLE_CONF['COMMENT_SYSTEM_ID'] = ''
+
+ if answer:
+ print("You need to provide the site identifier for your comment system. Consult the Nikola manual for details on what the value should be. (you can leave it empty and come back later)")
+ answer = ask('Comment system site identifier', '')
+ SAMPLE_CONF['COMMENT_SYSTEM_ID'] = answer
+
+ STORAGE = {'target': target}
+
+ questions = [
+ ('Questions about the site', None, None, None),
+ # query, default, toconf, destination
+ ('Destination', None, False, '!target'),
+ ('Site title', 'My Nikola Site', True, 'BLOG_TITLE'),
+ ('Site author', 'Nikola Tesla', True, 'BLOG_AUTHOR'),
+ ('Site author\'s e-mail', 'n.tesla@example.com', True, 'BLOG_EMAIL'),
+ ('Site description', 'This is a demo site for Nikola.', True, 'BLOG_DESCRIPTION'),
+ ('Site URL', 'http://getnikola.com/', True, 'SITE_URL'),
+ ('Questions about languages and locales', None, None, None),
+ (lhandler, None, True, True),
+ (tzhandler, None, True, True),
+ ('Questions about comments', None, None, None),
+ (chandler, None, True, True),
+ ]
+
+ print("Creating Nikola Site")
+ print("====================\n")
+ print("This is Nikola v{0}. We will now ask you a few easy questions about your new site.".format(nikola.__version__))
+ print("If you do not want to answer and want to go with the defaults instead, simply restart with the `-q` parameter.")
+
+ for query, default, toconf, destination in questions:
+ if target and destination == '!target':
+ # Skip the destination question if we know it already
+ pass
+ else:
+ if default is toconf is destination is None:
+ print('--- {0} ---'.format(query))
+ elif destination is True:
+ query(default, toconf)
+ else:
+ answer = ask(query, default)
+ if toconf:
+ SAMPLE_CONF[destination] = answer
+ if destination == '!target':
+ while not answer:
+ print(' ERROR: you need to specify a target directory.\n')
+ answer = ask(query, default)
+ STORAGE['target'] = answer
+
+ print("\nThat's it, Nikola is now configured. Make sure to edit conf.py to your liking.")
+ print("If you are looking for themes and addons, check out http://themes.getnikola.com/ and http://plugins.getnikola.com/.")
+ print("Have fun!")
+ return STORAGE
def _execute(self, options={}, args=None):
"""Create a new site."""
- if not args:
- print("Usage: nikola init folder [options]")
+ try:
+ target = args[0]
+ except IndexError:
+ target = None
+ if not options.get('quiet'):
+ st = self.ask_questions(target=target)
+ try:
+ if not target:
+ target = st['target']
+ except KeyError:
+ pass
+
+ if not target:
+ print("Usage: nikola init [--demo] [--quiet] folder")
+ print("""
+Options:
+ -q, --quiet Do not ask questions about config.
+ -d, --demo Create a site filled with example data.""")
return False
- target = args[0]
- if not options or not options.get('demo'):
+ if not options.get('demo'):
self.create_empty_site(target)
LOGGER.info('Created empty site at {0}.'.format(target))
else:
diff --git a/nikola/plugins/command/install_plugin.plugin b/nikola/plugins/command/install_plugin.plugin
deleted file mode 100644
index 3dbabd8..0000000
--- a/nikola/plugins/command/install_plugin.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = install_plugin
-Module = install_plugin
-
-[Documentation]
-Author = Roberto Alsina and Chris Warrick
-Version = 0.1
-Website = http://getnikola.com
-Description = Install a plugin into the current site.
-
diff --git a/nikola/plugins/command/install_plugin.py b/nikola/plugins/command/install_plugin.py
deleted file mode 100644
index 34223c0..0000000
--- a/nikola/plugins/command/install_plugin.py
+++ /dev/null
@@ -1,188 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-from __future__ import print_function
-import codecs
-import os
-import json
-import shutil
-import subprocess
-from io import BytesIO
-
-import pygments
-from pygments.lexers import PythonLexer
-from pygments.formatters import TerminalFormatter
-
-try:
- import requests
-except ImportError:
- requests = None # NOQA
-
-from nikola.plugin_categories import Command
-from nikola import utils
-
-LOGGER = utils.get_logger('install_plugin', utils.STDERR_HANDLER)
-
-
-# Stolen from textwrap in Python 3.3.2.
-def indent(text, prefix, predicate=None): # NOQA
- """Adds 'prefix' to the beginning of selected lines in 'text'.
-
- If 'predicate' is provided, 'prefix' will only be added to the lines
- where 'predicate(line)' is True. If 'predicate' is not provided,
- it will default to adding 'prefix' to all non-empty lines that do not
- consist solely of whitespace characters.
- """
- if predicate is None:
- def predicate(line):
- return line.strip()
-
- def prefixed_lines():
- for line in text.splitlines(True):
- yield (prefix + line if predicate(line) else line)
- return ''.join(prefixed_lines())
-
-
-class CommandInstallPlugin(Command):
- """Install a plugin."""
-
- name = "install_plugin"
- doc_usage = "[[-u] plugin_name] | [[-u] -l]"
- doc_purpose = "install plugin into current site"
- output_dir = 'plugins'
- cmd_options = [
- {
- 'name': 'list',
- 'short': 'l',
- 'long': 'list',
- 'type': bool,
- 'default': False,
- 'help': 'Show list of available plugins.'
- },
- {
- 'name': 'url',
- 'short': 'u',
- 'long': 'url',
- 'type': str,
- 'help': "URL for the plugin repository (default: "
- "http://plugins.getnikola.com/v6/plugins.json)",
- 'default': 'http://plugins.getnikola.com/v6/plugins.json'
- },
- ]
-
- def _execute(self, options, args):
- """Install plugin into current site."""
- if requests is None:
- utils.req_missing(['requests'], 'install plugins')
-
- listing = options['list']
- url = options['url']
- if args:
- name = args[0]
- else:
- name = None
-
- if name is None and not listing:
- LOGGER.error("This command needs either a plugin name or the -l option.")
- return False
- data = requests.get(url).text
- data = json.loads(data)
- if listing:
- print("Plugins:")
- print("--------")
- for plugin in sorted(data.keys()):
- print(plugin)
- return True
- else:
- self.do_install(name, data)
-
- def do_install(self, name, data):
- if name in data:
- utils.makedirs(self.output_dir)
- LOGGER.info('Downloading: ' + data[name])
- zip_file = BytesIO()
- zip_file.write(requests.get(data[name]).content)
- LOGGER.info('Extracting: {0} into plugins'.format(name))
- utils.extract_all(zip_file, 'plugins')
- dest_path = os.path.join('plugins', name)
- else:
- try:
- plugin_path = utils.get_plugin_path(name)
- except:
- LOGGER.error("Can't find plugin " + name)
- return False
-
- utils.makedirs(self.output_dir)
- dest_path = os.path.join(self.output_dir, name)
- if os.path.exists(dest_path):
- LOGGER.error("{0} is already installed".format(name))
- return False
-
- LOGGER.info('Copying {0} into plugins'.format(plugin_path))
- shutil.copytree(plugin_path, dest_path)
-
- reqpath = os.path.join(dest_path, 'requirements.txt')
- if os.path.exists(reqpath):
- LOGGER.notice('This plugin has Python dependencies.')
- LOGGER.info('Installing dependencies with pip...')
- try:
- subprocess.check_call(('pip', 'install', '-r', reqpath))
- except subprocess.CalledProcessError:
- LOGGER.error('Could not install the dependencies.')
- print('Contents of the requirements.txt file:\n')
- with codecs.open(reqpath, 'rb', 'utf-8') as fh:
- print(indent(fh.read(), 4 * ' '))
- print('You have to install those yourself or through a '
- 'package manager.')
- else:
- LOGGER.info('Dependency installation succeeded.')
- reqnpypath = os.path.join(dest_path, 'requirements-nonpy.txt')
- if os.path.exists(reqnpypath):
- LOGGER.notice('This plugin has third-party '
- 'dependencies you need to install '
- 'manually.')
- print('Contents of the requirements-nonpy.txt file:\n')
- with codecs.open(reqnpypath, 'rb', 'utf-8') as fh:
- for l in fh.readlines():
- i, j = l.split('::')
- print(indent(i.strip(), 4 * ' '))
- print(indent(j.strip(), 8 * ' '))
- print()
-
- print('You have to install those yourself or through a package '
- 'manager.')
- confpypath = os.path.join(dest_path, 'conf.py.sample')
- if os.path.exists(confpypath):
- LOGGER.notice('This plugin has a sample config file. Integrate it with yours in order to make this plugin work!')
- print('Contents of the conf.py.sample file:\n')
- with codecs.open(confpypath, 'rb', 'utf-8') as fh:
- if self.site.colorful:
- print(indent(pygments.highlight(
- fh.read(), PythonLexer(), TerminalFormatter()),
- 4 * ' '))
- else:
- print(indent(fh.read(), 4 * ' '))
- return True
diff --git a/nikola/plugins/command/install_theme.py b/nikola/plugins/command/install_theme.py
index 47c73b4..859bd56 100644
--- a/nikola/plugins/command/install_theme.py
+++ b/nikola/plugins/command/install_theme.py
@@ -87,8 +87,8 @@ class CommandInstallTheme(Command):
'long': 'url',
'type': str,
'help': "URL for the theme repository (default: "
- "http://themes.getnikola.com/v6/themes.json)",
- 'default': 'http://themes.getnikola.com/v6/themes.json'
+ "http://themes.getnikola.com/v7/themes.json)",
+ 'default': 'http://themes.getnikola.com/v7/themes.json'
},
]
diff --git a/nikola/plugins/command/mincss.py b/nikola/plugins/command/mincss.py
deleted file mode 100644
index 0193458..0000000
--- a/nikola/plugins/command/mincss.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-from __future__ import print_function, unicode_literals
-import os
-import sys
-
-try:
- from mincss.processor import Processor
-except ImportError:
- Processor = None
-
-from nikola.plugin_categories import Command
-from nikola.utils import req_missing, get_logger, STDERR_HANDLER
-
-
-class CommandMincss(Command):
- """Check the generated site."""
- name = "mincss"
-
- doc_usage = ""
- doc_purpose = "apply mincss to the generated site"
-
- logger = get_logger('mincss', STDERR_HANDLER)
-
- def _execute(self, options, args):
- """Apply mincss the generated site."""
- output_folder = self.site.config['OUTPUT_FOLDER']
- if Processor is None:
- req_missing(['mincss'], 'use the "mincss" command')
- return
-
- p = Processor(preserve_remote_urls=False)
- urls = []
- css_files = {}
- for root, dirs, files in os.walk(output_folder):
- for f in files:
- url = os.path.join(root, f)
- if url.endswith('.css'):
- fname = os.path.basename(url)
- if fname in css_files:
- self.logger.error("You have two CSS files with the same name and that confuses me.")
- sys.exit(1)
- css_files[fname] = url
- if not f.endswith('.html'):
- continue
- urls.append(url)
- p.process(*urls)
- for inline in p.links:
- fname = os.path.basename(inline.href)
- with open(css_files[fname], 'wb+') as outf:
- outf.write(inline.after)
diff --git a/nikola/plugins/command/new_page.py b/nikola/plugins/command/new_page.py
index 39c0c1d..f07ba39 100644
--- a/nikola/plugins/command/new_page.py
+++ b/nikola/plugins/command/new_page.py
@@ -59,6 +59,13 @@ class CommandNewPage(Command):
'help': 'Create the page with separate metadata (two file format)'
},
{
+ 'name': 'edit',
+ 'short': 'e',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Open the page (and meta file, if any) in $EDITOR after creation.'
+ },
+ {
'name': 'content_format',
'short': 'f',
'long': 'format',
diff --git a/nikola/plugins/command/new_post.py b/nikola/plugins/command/new_post.py
index cd37a75..42f77cc 100644
--- a/nikola/plugins/command/new_post.py
+++ b/nikola/plugins/command/new_post.py
@@ -29,8 +29,10 @@ import codecs
import datetime
import os
import sys
+import subprocess
from blinker import signal
+import dateutil.tz
from nikola.plugin_categories import Command
from nikola import utils
@@ -82,7 +84,7 @@ def get_default_compiler(is_post, compilers, post_pages):
return 'rest'
-def get_date(schedule=False, rule=None, last_date=None, force_today=False):
+def get_date(schedule=False, rule=None, last_date=None, tz=None, iso8601=False):
"""Returns a date stamp, given a recurrence rule.
schedule - bool:
@@ -94,33 +96,45 @@ def get_date(schedule=False, rule=None, last_date=None, force_today=False):
last_date - datetime:
timestamp of the last post
- force_today - bool:
- tries to schedule a post to today, if possible, even if the scheduled
- time has already passed in the day.
+ tz - tzinfo:
+ the timezone used for getting the current time.
+
+ iso8601 - bool:
+ whether to force ISO 8601 dates (instead of locale-specific ones)
+
"""
- date = now = datetime.datetime.now()
+ if tz is None:
+ tz = dateutil.tz.tzlocal()
+ date = now = datetime.datetime.now(tz)
if schedule:
try:
from dateutil import rrule
except ImportError:
LOGGER.error('To use the --schedule switch of new_post, '
'you have to install the "dateutil" package.')
- rrule = None
+ rrule = None # NOQA
if schedule and rrule and rule:
- if last_date and last_date.tzinfo:
- # strip tzinfo for comparisons
- last_date = last_date.replace(tzinfo=None)
try:
rule_ = rrule.rrulestr(rule, dtstart=last_date)
except Exception:
LOGGER.error('Unable to parse rule string, using current time.')
else:
- # Try to post today, instead of tomorrow, if no other post today.
- if force_today:
- now = now.replace(hour=0, minute=0, second=0, microsecond=0)
date = rule_.after(max(now, last_date or now), last_date is None)
- return date.strftime('%Y/%m/%d %H:%M:%S')
+
+ offset = tz.utcoffset(now)
+ offset_sec = (offset.days * 24 * 3600 + offset.seconds)
+ offset_hrs = offset_sec // 3600
+ offset_min = offset_sec % 3600
+ if iso8601:
+ tz_str = '{0:+03d}:{1:02d}'.format(offset_hrs, offset_min // 60)
+ else:
+ if offset:
+ tz_str = ' UTC{0:+03d}:{1:02d}'.format(offset_hrs, offset_min // 60)
+ else:
+ tz_str = ' UTC'
+
+ return date.strftime('%Y-%m-%d %H:%M:%S') + tz_str
class CommandNewPost(Command):
@@ -168,6 +182,13 @@ class CommandNewPost(Command):
'help': 'Create the post with separate metadata (two file format)'
},
{
+ 'name': 'edit',
+ 'short': 'e',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Open the post (and meta file, if any) in $EDITOR after creation.'
+ },
+ {
'name': 'content_format',
'short': 'f',
'long': 'format',
@@ -242,31 +263,44 @@ class CommandNewPost(Command):
print("Creating New {0}".format(content_type.title()))
print("-----------------\n")
- if title is None:
- print("Enter title: ", end='')
- # WHY, PYTHON3???? WHY?
- sys.stdout.flush()
- title = sys.stdin.readline()
- else:
+ if title is not None:
print("Title:", title)
+ else:
+ while not title:
+ title = utils.ask('Title')
+
if isinstance(title, utils.bytes_str):
- title = title.decode(sys.stdin.encoding)
+ try:
+ title = title.decode(sys.stdin.encoding)
+ except AttributeError: # for tests
+ title = title.decode('utf-8')
+
title = title.strip()
if not path:
slug = utils.slugify(title)
else:
if isinstance(path, utils.bytes_str):
- path = path.decode(sys.stdin.encoding)
+ try:
+ path = path.decode(sys.stdin.encoding)
+ except AttributeError: # for tests
+ path = path.decode('utf-8')
slug = utils.slugify(os.path.splitext(os.path.basename(path))[0])
# Calculate the date to use for the content
schedule = options['schedule'] or self.site.config['SCHEDULE_ALL']
rule = self.site.config['SCHEDULE_RULE']
- force_today = self.site.config['SCHEDULE_FORCE_TODAY']
self.site.scan_posts()
timeline = self.site.timeline
last_date = None if not timeline else timeline[0].date
- date = get_date(schedule, rule, last_date, force_today)
- data = [title, slug, date, tags]
+ date = get_date(schedule, rule, last_date, self.site.tzinfo, self.site.config['FORCE_ISO8601'])
+ data = {
+ 'title': title,
+ 'slug': slug,
+ 'date': date,
+ 'tags': tags,
+ 'link': '',
+ 'description': '',
+ 'type': 'text',
+ }
output_path = os.path.dirname(entry[0])
meta_path = os.path.join(output_path, slug + ".meta")
pattern = os.path.basename(entry[0])
@@ -284,19 +318,34 @@ class CommandNewPost(Command):
d_name = os.path.dirname(txt_path)
utils.makedirs(d_name)
metadata = self.site.config['ADDITIONAL_METADATA']
+
+ # Override onefile if not really supported.
+ if not compiler_plugin.supports_onefile and onefile:
+ onefile = False
+ LOGGER.warn('This compiler does not support one-file posts.')
+
+ content = "Write your {0} here.".format('page' if is_page else 'post')
compiler_plugin.create_post(
- txt_path, onefile, title=title,
+ txt_path, content=content, onefile=onefile, title=title,
slug=slug, date=date, tags=tags, is_page=is_page, **metadata)
event = dict(path=txt_path)
if not onefile: # write metadata file
with codecs.open(meta_path, "wb+", "utf8") as fd:
- fd.write('\n'.join(data))
- with codecs.open(txt_path, "wb+", "utf8") as fd:
- fd.write("Write your {0} here.".format(content_type))
+ fd.write(utils.write_metadata(data))
LOGGER.info("Your {0}'s metadata is at: {1}".format(content_type, meta_path))
event['meta_path'] = meta_path
LOGGER.info("Your {0}'s text is at: {1}".format(content_type, txt_path))
signal('new_' + content_type).send(self, **event)
+
+ if options['edit']:
+ editor = os.getenv('EDITOR')
+ to_run = [editor, txt_path]
+ if not onefile:
+ to_run.append(meta_path)
+ if editor:
+ subprocess.call(to_run)
+ else:
+ LOGGER.error('$EDITOR not set, cannot edit the post. Please do it manually.')
diff --git a/nikola/plugins/command/planetoid.plugin b/nikola/plugins/command/planetoid.plugin
deleted file mode 100644
index e767f31..0000000
--- a/nikola/plugins/command/planetoid.plugin
+++ /dev/null
@@ -1,9 +0,0 @@
-[Core]
-Name = planetoid
-Module = planetoid
-
-[Documentation]
-Author = Roberto Alsina
-Version = 0.1
-Website = http://getnikola.com
-Description = Maintain a planet-like site
diff --git a/nikola/plugins/command/planetoid/__init__.py b/nikola/plugins/command/planetoid/__init__.py
deleted file mode 100644
index fe1a59b..0000000
--- a/nikola/plugins/command/planetoid/__init__.py
+++ /dev/null
@@ -1,289 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-from __future__ import print_function, unicode_literals
-import codecs
-import datetime
-import hashlib
-from optparse import OptionParser
-import os
-import sys
-
-from doit.tools import timeout
-from nikola.plugin_categories import Command, Task
-from nikola.utils import config_changed, req_missing, get_logger, STDERR_HANDLER
-
-LOGGER = get_logger('planetoid', STDERR_HANDLER)
-
-try:
- import feedparser
-except ImportError:
- feedparser = None # NOQA
-
-try:
- import peewee
-except ImportError:
- peewee = None
-
-
-if peewee is not None:
- class Feed(peewee.Model):
- name = peewee.CharField()
- url = peewee.CharField(max_length=200)
- last_status = peewee.CharField(null=True)
- etag = peewee.CharField(max_length=200)
- last_modified = peewee.DateTimeField()
-
- class Entry(peewee.Model):
- date = peewee.DateTimeField()
- feed = peewee.ForeignKeyField(Feed)
- content = peewee.TextField(max_length=20000)
- link = peewee.CharField(max_length=200)
- title = peewee.CharField(max_length=200)
- guid = peewee.CharField(max_length=200)
-
-
-class Planetoid(Command, Task):
- """Maintain a planet-like thing."""
- name = "planetoid"
-
- def init_db(self):
- # setup database
- Feed.create_table(fail_silently=True)
- Entry.create_table(fail_silently=True)
-
- def gen_tasks(self):
- if peewee is None or sys.version_info[0] == 3:
- if sys.version_info[0] == 3:
- message = 'Peewee, a requirement of the "planetoid" command, is currently incompatible with Python 3.'
- else:
- req_missing('peewee', 'use the "planetoid" command')
- message = ''
- yield {
- 'basename': self.name,
- 'name': '',
- 'verbosity': 2,
- 'actions': ['echo "%s"' % message]
- }
- else:
- self.init_db()
- self.load_feeds()
- for task in self.task_update_feeds():
- yield task
- for task in self.task_generate_posts():
- yield task
- yield {
- 'basename': self.name,
- 'name': '',
- 'actions': [],
- 'file_dep': ['feeds'],
- 'task_dep': [
- self.name + "_fetch_feed",
- self.name + "_generate_posts",
- ]
- }
-
- def run(self, *args):
- parser = OptionParser(usage="nikola %s [options]" % self.name)
- (options, args) = parser.parse_args(list(args))
-
- def load_feeds(self):
- "Read the feeds file, add it to the database."
- feeds = []
- feed = name = None
- for line in codecs.open('feeds', 'r', 'utf-8'):
- line = line.strip()
- if line.startswith("#"):
- continue
- elif line.startswith('http'):
- feed = line
- elif line:
- name = line
- if feed and name:
- feeds.append([feed, name])
- feed = name = None
-
- def add_feed(name, url):
- f = Feed.create(
- name=name,
- url=url,
- etag='foo',
- last_modified=datetime.datetime(1970, 1, 1),
- )
- f.save()
-
- def update_feed_url(feed, url):
- feed.url = url
- feed.save()
-
- for feed, name in feeds:
- f = Feed.select().where(Feed.name == name)
- if not list(f):
- add_feed(name, feed)
- elif list(f)[0].url != feed:
- update_feed_url(list(f)[0], feed)
-
- def task_update_feeds(self):
- """Download feed contents, add entries to the database."""
- def update_feed(feed):
- modified = feed.last_modified.timetuple()
- etag = feed.etag
- try:
- parsed = feedparser.parse(
- feed.url,
- etag=etag,
- modified=modified
- )
- feed.last_status = str(parsed.status)
- except: # Probably a timeout
- # TODO: log failure
- return
- if parsed.feed.get('title'):
- LOGGER.info(parsed.feed.title)
- else:
- LOGGER.info(feed.url)
- feed.etag = parsed.get('etag', 'foo')
- modified = tuple(parsed.get('date_parsed', (1970, 1, 1)))[:6]
- LOGGER.info("==========>", modified)
- modified = datetime.datetime(*modified)
- feed.last_modified = modified
- feed.save()
- # No point in adding items from missinfg feeds
- if parsed.status > 400:
- # TODO log failure
- return
- for entry_data in parsed.entries:
- LOGGER.info("=========================================")
- date = entry_data.get('published_parsed', None)
- if date is None:
- date = entry_data.get('updated_parsed', None)
- if date is None:
- LOGGER.error("Can't parse date from:\n", entry_data)
- return False
- LOGGER.info("DATE:===>", date)
- date = datetime.datetime(*(date[:6]))
- title = "%s: %s" % (feed.name, entry_data.get('title', 'Sin título'))
- content = entry_data.get('content', None)
- if content:
- content = content[0].value
- if not content:
- content = entry_data.get('description', None)
- if not content:
- content = entry_data.get('summary', 'Sin contenido')
- guid = str(entry_data.get('guid', entry_data.link))
- link = entry_data.link
- LOGGER.info(repr([date, title]))
- e = list(Entry.select().where(Entry.guid == guid))
- LOGGER.info(
- repr(dict(
- date=date,
- title=title,
- content=content,
- guid=guid,
- feed=feed,
- link=link,
- ))
- )
- if not e:
- entry = Entry.create(
- date=date,
- title=title,
- content=content,
- guid=guid,
- feed=feed,
- link=link,
- )
- else:
- entry = e[0]
- entry.date = date
- entry.title = title
- entry.content = content
- entry.link = link
- entry.save()
- flag = False
- for feed in Feed.select():
- flag = True
- task = {
- 'basename': self.name + "_fetch_feed",
- 'name': str(feed.url),
- 'actions': [(update_feed, (feed, ))],
- 'uptodate': [timeout(datetime.timedelta(minutes=
- self.site.config.get('PLANETOID_REFRESH', 60)))],
- }
- yield task
- if not flag:
- yield {
- 'basename': self.name + "_fetch_feed",
- 'name': '',
- 'actions': [],
- }
-
- def task_generate_posts(self):
- """Generate post files for the blog entries."""
- def gen_id(entry):
- h = hashlib.md5()
- h.update(entry.feed.name.encode('utf8'))
- h.update(entry.guid)
- return h.hexdigest()
-
- def generate_post(entry):
- unique_id = gen_id(entry)
- meta_path = os.path.join('posts', unique_id + '.meta')
- post_path = os.path.join('posts', unique_id + '.txt')
- with codecs.open(meta_path, 'wb+', 'utf8') as fd:
- fd.write('%s\n' % entry.title.replace('\n', ' '))
- fd.write('%s\n' % unique_id)
- fd.write('%s\n' % entry.date.strftime('%Y/%m/%d %H:%M'))
- fd.write('\n')
- fd.write('%s\n' % entry.link)
- with codecs.open(post_path, 'wb+', 'utf8') as fd:
- fd.write('.. raw:: html\n\n')
- content = entry.content
- if not content:
- content = 'Sin contenido'
- for line in content.splitlines():
- fd.write(' %s\n' % line)
-
- if not os.path.isdir('posts'):
- os.mkdir('posts')
- flag = False
- for entry in Entry.select().order_by(Entry.date.desc()):
- flag = True
- entry_id = gen_id(entry)
- yield {
- 'basename': self.name + "_generate_posts",
- 'targets': [os.path.join('posts', entry_id + '.meta'), os.path.join('posts', entry_id + '.txt')],
- 'name': entry_id,
- 'actions': [(generate_post, (entry,))],
- 'uptodate': [config_changed({1: entry})],
- 'task_dep': [self.name + "_fetch_feed"],
- }
- if not flag:
- yield {
- 'basename': self.name + "_generate_posts",
- 'name': '',
- 'actions': [],
- }
diff --git a/nikola/plugins/command/plugin.plugin b/nikola/plugins/command/plugin.plugin
new file mode 100644
index 0000000..d2bca92
--- /dev/null
+++ b/nikola/plugins/command/plugin.plugin
@@ -0,0 +1,10 @@
+[Core]
+Name = plugin
+Module = plugin
+
+[Documentation]
+Author = Roberto Alsina and Chris Warrick
+Version = 0.2
+Website = http://getnikola.com
+Description = Manage Nikola plugins
+
diff --git a/nikola/plugins/command/plugin.py b/nikola/plugins/command/plugin.py
new file mode 100644
index 0000000..df0e7a4
--- /dev/null
+++ b/nikola/plugins/command/plugin.py
@@ -0,0 +1,319 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2012-2014 Roberto Alsina and others.
+
+# Permission is hereby granted, free of charge, to any
+# person obtaining a copy of this software and associated
+# documentation files (the "Software"), to deal in the
+# Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the
+# Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice
+# shall be included in all copies or substantial portions of
+# the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+from __future__ import print_function
+import codecs
+from io import BytesIO
+import os
+import shutil
+import subprocess
+import sys
+
+import pygments
+from pygments.lexers import PythonLexer
+from pygments.formatters import TerminalFormatter
+
+try:
+ import requests
+except ImportError:
+ requests = None # NOQA
+
+from nikola.plugin_categories import Command
+from nikola import utils
+
+LOGGER = utils.get_logger('plugin', utils.STDERR_HANDLER)
+
+
+# Stolen from textwrap in Python 3.3.2.
+def indent(text, prefix, predicate=None): # NOQA
+ """Adds 'prefix' to the beginning of selected lines in 'text'.
+
+ If 'predicate' is provided, 'prefix' will only be added to the lines
+ where 'predicate(line)' is True. If 'predicate' is not provided,
+ it will default to adding 'prefix' to all non-empty lines that do not
+ consist solely of whitespace characters.
+ """
+ if predicate is None:
+ def predicate(line):
+ return line.strip()
+
+ def prefixed_lines():
+ for line in text.splitlines(True):
+ yield (prefix + line if predicate(line) else line)
+ return ''.join(prefixed_lines())
+
+
+class CommandPlugin(Command):
+ """Manage plugins."""
+
+ json = None
+ name = "plugin"
+ doc_usage = "[[-u][--user] --install name] | [[-u] [-l |--upgrade|--list-installed] | [--uninstall name]]"
+ doc_purpose = "manage plugins"
+ output_dir = None
+ needs_config = False
+ cmd_options = [
+ {
+ 'name': 'install',
+ 'short': 'i',
+ 'long': 'install',
+ 'type': str,
+ 'default': '',
+ 'help': 'Install a plugin.',
+ },
+ {
+ 'name': 'uninstall',
+ 'long': 'uninstall',
+ 'short': 'r',
+ 'type': str,
+ 'default': '',
+ 'help': 'Uninstall a plugin.'
+ },
+ {
+ 'name': 'list',
+ 'short': 'l',
+ 'long': 'list',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Show list of available plugins.'
+ },
+ {
+ 'name': 'url',
+ 'short': 'u',
+ 'long': 'url',
+ 'type': str,
+ 'help': "URL for the plugin repository (default: "
+ "http://plugins.getnikola.com/v7/plugins.json)",
+ 'default': 'http://plugins.getnikola.com/v7/plugins.json'
+ },
+ {
+ 'name': 'user',
+ 'long': 'user',
+ 'type': bool,
+ 'help': "Install user-wide, available for all sites.",
+ 'default': False
+ },
+ {
+ 'name': 'upgrade',
+ 'long': 'upgrade',
+ 'type': bool,
+ 'help': "Upgrade all installed plugins.",
+ 'default': False
+ },
+ {
+ 'name': 'list_installed',
+ 'long': 'list-installed',
+ 'type': bool,
+ 'help': "List the installed plugins with their location.",
+ 'default': False
+ },
+ ]
+
+ def _execute(self, options, args):
+ """Install plugin into current site."""
+ url = options['url']
+ user_mode = options['user']
+
+ # See the "mode" we need to operate in
+ install = options.get('install')
+ uninstall = options.get('uninstall')
+ upgrade = options.get('upgrade')
+ list_available = options.get('list')
+ list_installed = options.get('list_installed')
+ command_count = [bool(x) for x in (
+ install,
+ uninstall,
+ upgrade,
+ list_available,
+ list_installed)].count(True)
+ if command_count > 1 or command_count == 0:
+ print(self.help())
+ return
+
+ if not self.site.configured and not user_mode and install:
+ LOGGER.notice('No site found, assuming --user')
+ user_mode = True
+
+ if user_mode:
+ self.output_dir = os.path.expanduser('~/.nikola/plugins')
+ else:
+ self.output_dir = 'plugins'
+
+ if list_available:
+ self.list_available(url)
+ elif list_installed:
+ self.list_installed()
+ elif upgrade:
+ self.do_upgrade(url)
+ elif uninstall:
+ self.do_uninstall(uninstall)
+ elif install:
+ self.do_install(url, install)
+
+ def list_available(self, url):
+ data = self.get_json(url)
+ print("Available Plugins:")
+ print("------------------")
+ for plugin in sorted(data.keys()):
+ print(plugin)
+ return True
+
+ def list_installed(self):
+ plugins = []
+ for plugin in self.site.plugin_manager.getAllPlugins():
+ p = plugin.path
+ if os.path.isdir(p):
+ p = p + os.sep
+ else:
+ p = p + '.py'
+ plugins.append([plugin.name, p])
+
+ plugins.sort()
+ for name, path in plugins:
+ print('{0} at {1}'.format(name, path))
+
+ def do_upgrade(self, url):
+ LOGGER.warning('This is not very smart, it just reinstalls some plugins and hopes for the best')
+ data = self.get_json(url)
+ plugins = []
+ for plugin in self.site.plugin_manager.getAllPlugins():
+ p = plugin.path
+ if os.path.isdir(p):
+ p = p + os.sep
+ else:
+ p = p + '.py'
+ if plugin.name in data:
+ plugins.append([plugin.name, p])
+ print('Will upgrade {0} plugins: {1}'.format(len(plugins), ', '.join(n for n, _ in plugins)))
+ for name, path in plugins:
+ print('Upgrading {0}'.format(name))
+ p = path
+ while True:
+ tail, head = os.path.split(path)
+ if head == 'plugins':
+ self.output_dir = path
+ break
+ elif tail == '':
+ LOGGER.error("Can't find the plugins folder for path: {0}".format(p))
+ return False
+ else:
+ path = tail
+ self.do_install(url, name)
+
+ def do_install(self, url, name):
+ data = self.get_json(url)
+ if name in data:
+ utils.makedirs(self.output_dir)
+ LOGGER.info('Downloading: ' + data[name])
+ zip_file = BytesIO()
+ zip_file.write(requests.get(data[name]).content)
+ LOGGER.info('Extracting: {0} into {1}/'.format(name, self.output_dir))
+ utils.extract_all(zip_file, self.output_dir)
+ dest_path = os.path.join(self.output_dir, name)
+ else:
+ try:
+ plugin_path = utils.get_plugin_path(name)
+ except:
+ LOGGER.error("Can't find plugin " + name)
+ return False
+
+ utils.makedirs(self.output_dir)
+ dest_path = os.path.join(self.output_dir, name)
+ if os.path.exists(dest_path):
+ LOGGER.error("{0} is already installed".format(name))
+ return False
+
+ LOGGER.info('Copying {0} into plugins'.format(plugin_path))
+ shutil.copytree(plugin_path, dest_path)
+
+ reqpath = os.path.join(dest_path, 'requirements.txt')
+ if os.path.exists(reqpath):
+ LOGGER.notice('This plugin has Python dependencies.')
+ LOGGER.info('Installing dependencies with pip...')
+ try:
+ subprocess.check_call(('pip', 'install', '-r', reqpath))
+ except subprocess.CalledProcessError:
+ LOGGER.error('Could not install the dependencies.')
+ print('Contents of the requirements.txt file:\n')
+ with codecs.open(reqpath, 'rb', 'utf-8') as fh:
+ print(indent(fh.read(), 4 * ' '))
+ print('You have to install those yourself or through a '
+ 'package manager.')
+ else:
+ LOGGER.info('Dependency installation succeeded.')
+ reqnpypath = os.path.join(dest_path, 'requirements-nonpy.txt')
+ if os.path.exists(reqnpypath):
+ LOGGER.notice('This plugin has third-party '
+ 'dependencies you need to install '
+ 'manually.')
+ print('Contents of the requirements-nonpy.txt file:\n')
+ with codecs.open(reqnpypath, 'rb', 'utf-8') as fh:
+ for l in fh.readlines():
+ i, j = l.split('::')
+ print(indent(i.strip(), 4 * ' '))
+ print(indent(j.strip(), 8 * ' '))
+ print()
+
+ print('You have to install those yourself or through a package '
+ 'manager.')
+ confpypath = os.path.join(dest_path, 'conf.py.sample')
+ if os.path.exists(confpypath):
+ LOGGER.notice('This plugin has a sample config file. Integrate it with yours in order to make this plugin work!')
+ print('Contents of the conf.py.sample file:\n')
+ with codecs.open(confpypath, 'rb', 'utf-8') as fh:
+ if self.site.colorful:
+ print(indent(pygments.highlight(
+ fh.read(), PythonLexer(), TerminalFormatter()),
+ 4 * ' '))
+ else:
+ print(indent(fh.read(), 4 * ' '))
+ return True
+
+ def do_uninstall(self, name):
+ for plugin in self.site.plugin_manager.getAllPlugins(): # FIXME: this is repeated thrice
+ p = plugin.path
+ if os.path.isdir(p):
+ p = p + os.sep
+ else:
+ p = os.path.dirname(p)
+ if name == plugin.name: # Uninstall this one
+ LOGGER.warning('About to uninstall plugin: {0}'.format(name))
+ LOGGER.warning('This will delete {0}'.format(p))
+ inpf = raw_input if sys.version_info[0] == 2 else input
+ sure = inpf('Are you sure? [y/n] ')
+ if sure.lower().startswith('y'):
+ LOGGER.warning('Removing {0}'.format(p))
+ shutil.rmtree(p)
+ return True
+ LOGGER.error('Unknown plugin: {0}'.format(name))
+ return False
+
+ def get_json(self, url):
+ if requests is None:
+ utils.req_missing(['requests'], 'install or list available plugins', python=True, optional=False)
+ if self.json is None:
+ self.json = requests.get(url).json()
+ return self.json
diff --git a/nikola/plugins/command/serve.py b/nikola/plugins/command/serve.py
index f27d1f7..623e2db 100644
--- a/nikola/plugins/command/serve.py
+++ b/nikola/plugins/command/serve.py
@@ -89,7 +89,11 @@ class CommandServe(Command):
server_url = "http://{0}:{1}/".format(options['address'], options['port'])
self.logger.info("Opening {0} in the default web browser ...".format(server_url))
webbrowser.open(server_url)
- httpd.serve_forever()
+ try:
+ httpd.serve_forever()
+ except KeyboardInterrupt:
+ self.logger.info("Server is shutting down.")
+ exit(130)
class OurHTTPRequestHandler(SimpleHTTPRequestHandler):
diff --git a/nikola/plugins/compile/asciidoc.plugin b/nikola/plugins/compile/asciidoc.plugin
deleted file mode 100644
index 47c5608..0000000
--- a/nikola/plugins/compile/asciidoc.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = asciidoc
-Module = asciidoc
-
-[Documentation]
-Author = Roberto Alsina
-Version = 0.1
-Website = http://getnikola.com
-Description = Compile ASCIIDoc into HTML
-
diff --git a/nikola/plugins/compile/asciidoc.py b/nikola/plugins/compile/asciidoc.py
deleted file mode 100644
index 68f96d9..0000000
--- a/nikola/plugins/compile/asciidoc.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-"""Implementation of compile_html based on asciidoc.
-
-You will need, of course, to install asciidoc
-
-"""
-
-import codecs
-import os
-import subprocess
-
-from nikola.plugin_categories import PageCompiler
-from nikola.utils import makedirs, req_missing
-
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
-
-
-class CompileAsciiDoc(PageCompiler):
- """Compile asciidoc into HTML."""
-
- name = "asciidoc"
- demote_headers = True
-
- def compile_html(self, source, dest, is_two_file=True):
- makedirs(os.path.dirname(dest))
- try:
- subprocess.check_call(('asciidoc', '-f', 'html', '-s', '-o', dest, source))
- except OSError as e:
- if e.strreror == 'No such file or directory':
- req_missing(['asciidoc'], 'build this site (compile with asciidoc)', python=False)
-
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
- metadata.update(self.default_metadata)
- metadata.update(kw)
- makedirs(os.path.dirname(path))
- with codecs.open(path, "wb+", "utf8") as fd:
- if onefile:
- fd.write("/////////////////////////////////////////////\n")
- for k, v in metadata.items():
- fd.write('.. {0}: {1}\n'.format(k, v))
- fd.write("/////////////////////////////////////////////\n")
- fd.write("\nWrite your {0} here.".format('page' if is_page else 'post'))
diff --git a/nikola/plugins/compile/bbcode.py b/nikola/plugins/compile/bbcode.py
deleted file mode 100644
index 0961ffe..0000000
--- a/nikola/plugins/compile/bbcode.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-"""Implementation of compile_html based on bbcode."""
-
-import codecs
-import os
-import re
-
-try:
- import bbcode
-except ImportError:
- bbcode = None # NOQA
-
-from nikola.plugin_categories import PageCompiler
-from nikola.utils import makedirs, req_missing
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
-
-
-class CompileBbcode(PageCompiler):
- """Compile bbcode into HTML."""
-
- name = "bbcode"
-
- def __init__(self):
- if bbcode is None:
- return
- self.parser = bbcode.Parser()
- self.parser.add_simple_formatter("note", "")
-
- def compile_html(self, source, dest, is_two_file=True):
- if bbcode is None:
- req_missing(['bbcode'], 'build this site (compile BBCode)')
- makedirs(os.path.dirname(dest))
- with codecs.open(dest, "w+", "utf8") as out_file:
- with codecs.open(source, "r", "utf8") as in_file:
- data = in_file.read()
- if not is_two_file:
- data = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1)[-1]
- output = self.parser.format(data)
- out_file.write(output)
-
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
- metadata.update(self.default_metadata)
- metadata.update(kw)
- makedirs(os.path.dirname(path))
- with codecs.open(path, "wb+", "utf8") as fd:
- if onefile:
- fd.write('[note]<!--\n')
- for k, v in metadata.items():
- fd.write('.. {0}: {1}\n'.format(k, v))
- fd.write('-->[/note]\n\n')
- fd.write("Write your {0} here.".format('page' if is_page else 'post'))
diff --git a/nikola/plugins/compile/html.py b/nikola/plugins/compile/html.py
index 09a9756..fff7f89 100644
--- a/nikola/plugins/compile/html.py
+++ b/nikola/plugins/compile/html.py
@@ -31,12 +31,7 @@ import re
import codecs
from nikola.plugin_categories import PageCompiler
-from nikola.utils import makedirs
-
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
+from nikola.utils import makedirs, write_metadata
_META_SEPARATOR = '(' + os.linesep * 2 + '|' + ('\n' * 2) + '|' + ("\r\n" * 2) + ')'
@@ -56,15 +51,20 @@ class CompileHtml(PageCompiler):
out_file.write(data)
return True
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
+ def create_post(self, path, **kw):
+ content = kw.pop('content', None)
+ onefile = kw.pop('onefile', False)
+ # is_page is not used by create_post as of now.
+ kw.pop('is_page', False)
+ metadata = {}
metadata.update(self.default_metadata)
metadata.update(kw)
makedirs(os.path.dirname(path))
+ if not content.endswith('\n'):
+ content += '\n'
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
- fd.write('<!-- \n')
- for k, v in metadata.items():
- fd.write('.. {0}: {1}\n'.format(k, v))
+ fd.write('<!--\n')
+ fd.write(write_metadata(metadata))
fd.write('-->\n\n')
- fd.write("\n<p>Write your {0} here.</p>\n".format('page' if is_page else 'post'))
+ fd.write(content)
diff --git a/nikola/plugins/compile/ipynb.plugin b/nikola/plugins/compile/ipynb.plugin
index 3d15bb0..e258d8a 100644
--- a/nikola/plugins/compile/ipynb.plugin
+++ b/nikola/plugins/compile/ipynb.plugin
@@ -3,7 +3,7 @@ Name = ipynb
Module = ipynb
[Documentation]
-Author = Damián Avila
+Author = Damian Avila
Version = 1.0
Website = http://www.oquanta.info
Description = Compile IPython notebooks into HTML
diff --git a/nikola/plugins/compile/ipynb/__init__.py b/nikola/plugins/compile/ipynb/__init__.py
index 2b1fd28..f4d554c 100644
--- a/nikola/plugins/compile/ipynb/__init__.py
+++ b/nikola/plugins/compile/ipynb/__init__.py
@@ -41,16 +41,12 @@ except ImportError:
from nikola.plugin_categories import PageCompiler
from nikola.utils import makedirs, req_missing
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
-
class CompileIPynb(PageCompiler):
"""Compile IPynb into HTML."""
name = "ipynb"
+ supports_onefile = False
def compile_html(self, source, dest, is_two_file=True):
if flag is None:
@@ -66,19 +62,15 @@ class CompileIPynb(PageCompiler):
(body, resources) = exportHtml.from_notebook_node(nb_json)
out_file.write(body)
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
- metadata.update(self.default_metadata)
- metadata.update(kw)
- d_name = os.path.dirname(path)
+ def create_post(self, path, **kw):
+ # content and onefile are ignored by ipynb.
+ kw.pop('content', None)
+ onefile = kw.pop('onefile', False)
+ kw.pop('is_page', False)
+
makedirs(os.path.dirname(path))
- meta_path = os.path.join(d_name, kw['slug'] + ".meta")
- with codecs.open(meta_path, "wb+", "utf8") as fd:
- fd.write('\n'.join((metadata['title'], metadata['slug'],
- metadata['date'], metadata['tags'],
- metadata['link'],
- metadata['description'], metadata['type'])))
- print("Your {0}'s metadata is at: {1}".format('page' if is_page else 'post', meta_path))
+ if onefile:
+ raise Exception('The one-file format is not supported by this compiler.')
with codecs.open(path, "wb+", "utf8") as fd:
fd.write("""{
"metadata": {
diff --git a/nikola/plugins/compile/markdown/__init__.py b/nikola/plugins/compile/markdown/__init__.py
index d0fa66a..4182626 100644
--- a/nikola/plugins/compile/markdown/__init__.py
+++ b/nikola/plugins/compile/markdown/__init__.py
@@ -34,30 +34,14 @@ import re
try:
from markdown import markdown
-
- from nikola.plugins.compile.markdown.mdx_nikola import NikolaExtension
- nikola_extension = NikolaExtension()
-
- from nikola.plugins.compile.markdown.mdx_gist import GistExtension
- gist_extension = GistExtension()
-
- from nikola.plugins.compile.markdown.mdx_podcast import PodcastExtension
- podcast_extension = PodcastExtension()
-
except ImportError:
markdown = None # NOQA
nikola_extension = None
gist_extension = None
podcast_extension = None
-
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
-
from nikola.plugin_categories import PageCompiler
-from nikola.utils import makedirs, req_missing
+from nikola.utils import makedirs, req_missing, write_metadata
class CompileMarkdown(PageCompiler):
@@ -65,9 +49,22 @@ class CompileMarkdown(PageCompiler):
name = "markdown"
demote_headers = True
- extensions = [gist_extension, nikola_extension, podcast_extension]
+ extensions = []
site = None
+ def set_site(self, site):
+ for plugin_info in site.plugin_manager.getPluginsOfCategory("MarkdownExtension"):
+ if plugin_info.name in site.config['DISABLED_PLUGINS']:
+ site.plugin_manager.removePluginFromCategory(plugin_info, "MarkdownExtension")
+ continue
+
+ site.plugin_manager.activatePluginByName(plugin_info.name)
+ plugin_info.plugin_object.set_site(site)
+ self.extensions.append(plugin_info.plugin_object)
+ plugin_info.plugin_object.short_help = plugin_info.description
+
+ return super(CompileMarkdown, self).set_site(site)
+
def compile_html(self, source, dest, is_two_file=True):
if markdown is None:
req_missing(['markdown'], 'build this site (compile Markdown)')
@@ -81,15 +78,21 @@ class CompileMarkdown(PageCompiler):
output = markdown(data, self.extensions)
out_file.write(output)
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
+ def create_post(self, path, **kw):
+ content = kw.pop('content', None)
+ onefile = kw.pop('onefile', False)
+ # is_page is not used by create_post as of now.
+ kw.pop('is_page', False)
+
+ metadata = {}
metadata.update(self.default_metadata)
metadata.update(kw)
makedirs(os.path.dirname(path))
+ if not content.endswith('\n'):
+ content += '\n'
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
fd.write('<!-- \n')
- for k, v in metadata.items():
- fd.write('.. {0}: {1}\n'.format(k, v))
+ fd.write(write_metadata(metadata))
fd.write('-->\n\n')
- fd.write("Write your {0} here.".format('page' if is_page else 'post'))
+ fd.write(content)
diff --git a/nikola/plugins/compile/bbcode.plugin b/nikola/plugins/compile/markdown/mdx_gist.plugin
index b3d9357..0e5c578 100644
--- a/nikola/plugins/compile/bbcode.plugin
+++ b/nikola/plugins/compile/markdown/mdx_gist.plugin
@@ -1,10 +1,9 @@
[Core]
-Name = bbcode
-Module = bbcode
+Name = mdx_gist
+Module = mdx_gist
[Documentation]
Author = Roberto Alsina
Version = 0.1
Website = http://getnikola.com
-Description = Compile BBCode into HTML
-
+Description = Extension for embedding gists
diff --git a/nikola/plugins/compile/markdown/mdx_gist.py b/nikola/plugins/compile/markdown/mdx_gist.py
index d92295d..247478b 100644
--- a/nikola/plugins/compile/markdown/mdx_gist.py
+++ b/nikola/plugins/compile/markdown/mdx_gist.py
@@ -117,10 +117,18 @@ Error Case: non-existent file:
'''
from __future__ import unicode_literals, print_function
-from markdown.extensions import Extension
-from markdown.inlinepatterns import Pattern
-from markdown.util import AtomicString
-from markdown.util import etree
+
+try:
+ from markdown.extensions import Extension
+ from markdown.inlinepatterns import Pattern
+ from markdown.util import AtomicString
+ from markdown.util import etree
+except ImportError:
+ # No need to catch this, if you try to use this without Markdown,
+ # the markdown compiler will fail first
+ Extension = Pattern = object
+
+from nikola.plugin_categories import MarkdownExtension
from nikola.utils import get_logger, req_missing, STDERR_HANDLER
LOGGER = get_logger('compile_markdown.mdx_gist', STDERR_HANDLER)
@@ -209,7 +217,7 @@ class GistPattern(Pattern):
return gist_elem
-class GistExtension(Extension):
+class GistExtension(MarkdownExtension, Extension):
def __init__(self, configs={}):
# set extension defaults
self.config = {}
diff --git a/nikola/plugins/command/mincss.plugin b/nikola/plugins/compile/markdown/mdx_nikola.plugin
index d394d06..7af52a4 100644
--- a/nikola/plugins/command/mincss.plugin
+++ b/nikola/plugins/compile/markdown/mdx_nikola.plugin
@@ -1,10 +1,9 @@
[Core]
-Name = mincss
-Module = mincss
+Name = mdx_nikola
+Module = mdx_nikola
[Documentation]
Author = Roberto Alsina
Version = 0.1
Website = http://getnikola.com
-Description = Apply mincss to the generated site
-
+Description = Nikola-specific Markdown extensions
diff --git a/nikola/plugins/compile/markdown/mdx_nikola.py b/nikola/plugins/compile/markdown/mdx_nikola.py
index b7c29a5..ca67511 100644
--- a/nikola/plugins/compile/markdown/mdx_nikola.py
+++ b/nikola/plugins/compile/markdown/mdx_nikola.py
@@ -27,23 +27,31 @@
"""Markdown Extension for Nikola-specific post-processing"""
from __future__ import unicode_literals
import re
-from markdown.postprocessors import Postprocessor
-from markdown.extensions import Extension
+try:
+ from markdown.postprocessors import Postprocessor
+ from markdown.extensions import Extension
+except ImportError:
+ # No need to catch this, if you try to use this without Markdown,
+ # the markdown compiler will fail first
+ Postprocessor = Extension = object
+
+from nikola.plugin_categories import MarkdownExtension
+
+# FIXME: duplicated with listings.py
+CODERE = re.compile('<div class="codehilite"><pre>(.*?)</pre></div>', flags=re.MULTILINE | re.DOTALL)
class NikolaPostProcessor(Postprocessor):
def run(self, text):
output = text
- # python-markdown's highlighter uses the class 'codehilite' to wrap
- # code, instead of the standard 'code'. None of the standard
- # pygments stylesheets use this class, so swap it to be 'code'
- output = re.sub(r'(<div[^>]+class="[^"]*)codehilite([^>]+)',
- r'\1code\2', output)
+ # python-markdown's highlighter uses <div class="codehilite"><pre>
+ # for code. We switch it to reST's <pre class="code">.
+ output = CODERE.sub('<pre class="code literal-block">\\1</pre>', output)
return output
-class NikolaExtension(Extension):
+class NikolaExtension(MarkdownExtension, Extension):
def extendMarkdown(self, md, md_globals):
pp = NikolaPostProcessor()
md.postprocessors.add('nikola_post_processor', pp, '_end')
diff --git a/nikola/plugins/compile/markdown/mdx_podcast.plugin b/nikola/plugins/compile/markdown/mdx_podcast.plugin
new file mode 100644
index 0000000..dc16044
--- /dev/null
+++ b/nikola/plugins/compile/markdown/mdx_podcast.plugin
@@ -0,0 +1,9 @@
+[Core]
+Name = mdx_podcast
+Module = mdx_podcast
+
+[Documentation]
+Author = Roberto Alsina
+Version = 0.1
+Website = http://getnikola.com
+Description = Markdown extensions for embedding podcasts and other audio files
diff --git a/nikola/plugins/compile/markdown/mdx_podcast.py b/nikola/plugins/compile/markdown/mdx_podcast.py
index b38b969..9a67910 100644
--- a/nikola/plugins/compile/markdown/mdx_podcast.py
+++ b/nikola/plugins/compile/markdown/mdx_podcast.py
@@ -39,9 +39,15 @@ Basic Example:
<p><audio src="http://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3"></audio></p>
'''
-from markdown.extensions import Extension
-from markdown.inlinepatterns import Pattern
-from markdown.util import etree
+from nikola.plugin_categories import MarkdownExtension
+try:
+ from markdown.extensions import Extension
+ from markdown.inlinepatterns import Pattern
+ from markdown.util import etree
+except ImportError:
+ # No need to catch this, if you try to use this without Markdown,
+ # the markdown compiler will fail first
+ Pattern = Extension = object
PODCAST_RE = r'\[podcast\](?P<url>.+)\[/podcast\]'
@@ -62,7 +68,7 @@ class PodcastPattern(Pattern):
return audio_elem
-class PodcastExtension(Extension):
+class PodcastExtension(MarkdownExtension, Extension):
def __init__(self, configs={}):
# set extension defaults
self.config = {}
diff --git a/nikola/plugins/compile/misaka.plugin b/nikola/plugins/compile/misaka.plugin
deleted file mode 100644
index fef6d71..0000000
--- a/nikola/plugins/compile/misaka.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = misaka
-Module = misaka
-
-[Documentation]
-Author = Chris Lee
-Version = 0.1
-Website = http://c133.org/
-Description = Compile Markdown into HTML with Mikasa instead of python-markdown
-
diff --git a/nikola/plugins/compile/misaka.py b/nikola/plugins/compile/misaka.py
deleted file mode 100644
index 4951c9f..0000000
--- a/nikola/plugins/compile/misaka.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2013-2014 Chris Lee and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-"""Implementation of compile_html based on misaka."""
-
-from __future__ import unicode_literals
-
-import codecs
-import os
-import re
-
-try:
- import misaka
-except ImportError:
- misaka = None # NOQA
- nikola_extension = None
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
-
- gist_extension = None
- podcast_extension = None
-
-from nikola.plugin_categories import PageCompiler
-from nikola.utils import makedirs, req_missing
-
-
-class CompileMisaka(PageCompiler):
- """Compile Misaka into HTML."""
-
- name = "misaka"
- demote_headers = True
-
- def __init__(self, *args, **kwargs):
- super(CompileMisaka, self).__init__(*args, **kwargs)
- if misaka is not None:
- self.ext = misaka.EXT_FENCED_CODE | misaka.EXT_STRIKETHROUGH | \
- misaka.EXT_AUTOLINK | misaka.EXT_NO_INTRA_EMPHASIS
-
- def compile_html(self, source, dest, is_two_file=True):
- if misaka is None:
- req_missing(['misaka'], 'build this site (compile with misaka)')
- makedirs(os.path.dirname(dest))
- with codecs.open(dest, "w+", "utf8") as out_file:
- with codecs.open(source, "r", "utf8") as in_file:
- data = in_file.read()
- if not is_two_file:
- data = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1)[-1]
- output = misaka.html(data, extensions=self.ext)
- out_file.write(output)
-
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
- metadata.update(self.default_metadata)
- metadata.update(kw)
- makedirs(os.path.dirname(path))
- with codecs.open(path, "wb+", "utf8") as fd:
- if onefile:
- fd.write('<!-- \n')
- for k, v in metadata.items():
- fd.write('.. {0}: {1}\n'.format(k, v))
- fd.write('-->\n\n')
- fd.write("\nWrite your {0} here.".format('page' if is_page else 'post'))
diff --git a/nikola/plugins/compile/pandoc.py b/nikola/plugins/compile/pandoc.py
index 654c7c8..6aa737e 100644
--- a/nikola/plugins/compile/pandoc.py
+++ b/nikola/plugins/compile/pandoc.py
@@ -35,12 +35,7 @@ import os
import subprocess
from nikola.plugin_categories import PageCompiler
-from nikola.utils import req_missing, makedirs
-
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
+from nikola.utils import req_missing, makedirs, write_metadata
class CompilePandoc(PageCompiler):
@@ -56,15 +51,20 @@ class CompilePandoc(PageCompiler):
if e.strreror == 'No such file or directory':
req_missing(['pandoc'], 'build this site (compile with pandoc)', python=False)
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
+ def create_post(self, path, **kw):
+ content = kw.pop('content', None)
+ onefile = kw.pop('onefile', False)
+ # is_page is not used by create_post as of now.
+ kw.pop('is_page', False)
+ metadata = {}
metadata.update(self.default_metadata)
metadata.update(kw)
makedirs(os.path.dirname(path))
+ if not content.endswith('\n'):
+ content += '\n'
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
- fd.write('<!-- \n')
- for k, v in metadata.items():
- fd.write('.. {0}: {1}\n'.format(k, v))
+ fd.write('<!--\n')
+ fd.write(write_metadata(metadata))
fd.write('-->\n\n')
- fd.write("Write your {0} here.".format('page' if is_page else 'post'))
+ fd.write(content)
diff --git a/nikola/plugins/compile/php.py b/nikola/plugins/compile/php.py
index 0a652a6..601f098 100644
--- a/nikola/plugins/compile/php.py
+++ b/nikola/plugins/compile/php.py
@@ -33,12 +33,7 @@ import shutil
import codecs
from nikola.plugin_categories import PageCompiler
-from nikola.utils import makedirs
-
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
+from nikola.utils import makedirs, write_metadata
class CompilePhp(PageCompiler):
@@ -50,18 +45,23 @@ class CompilePhp(PageCompiler):
makedirs(os.path.dirname(dest))
shutil.copyfile(source, dest)
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
+ def create_post(self, path, **kw):
+ content = kw.pop('content', None)
+ onefile = kw.pop('onefile', False)
+ # is_page is not used by create_post as of now.
+ kw.pop('is_page', False)
+ metadata = {}
metadata.update(self.default_metadata)
metadata.update(kw)
os.makedirs(os.path.dirname(path))
+ if not content.endswith('\n'):
+ content += '\n'
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
- fd.write('<!-- \n')
- for k, v in metadata.items():
- fd.write('.. {0}: {1}\n'.format(k, v))
+ fd.write('<!--\n')
+ fd.write(write_metadata(metadata))
fd.write('-->\n\n')
- fd.write("\n<p>Write your {0} here.</p>".format('page' if is_page else 'post'))
+ fd.write(content)
def extension(self):
return ".php"
diff --git a/nikola/plugins/compile/rest/__init__.py b/nikola/plugins/compile/rest/__init__.py
index 9a4e19b..a93199c 100644
--- a/nikola/plugins/compile/rest/__init__.py
+++ b/nikola/plugins/compile/rest/__init__.py
@@ -40,13 +40,8 @@ try:
except ImportError:
has_docutils = False
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
-
from nikola.plugin_categories import PageCompiler
-from nikola.utils import get_logger, makedirs, req_missing
+from nikola.utils import get_logger, makedirs, req_missing, write_metadata
class CompileRest(PageCompiler):
@@ -102,22 +97,25 @@ class CompileRest(PageCompiler):
else:
return False
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
+ def create_post(self, path, **kw):
+ content = kw.pop('content', None)
+ onefile = kw.pop('onefile', False)
+ # is_page is not used by create_post as of now.
+ kw.pop('is_page', False)
+ metadata = {}
metadata.update(self.default_metadata)
metadata.update(kw)
makedirs(os.path.dirname(path))
+ if not content.endswith('\n'):
+ content += '\n'
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
- for k, v in metadata.items():
- fd.write('.. {0}: {1}\n'.format(k, v))
- fd.write("\nWrite your {0} here.".format('page' if is_page else 'post'))
+ fd.write(write_metadata(metadata))
+ fd.write('\n' + content)
def set_site(self, site):
for plugin_info in site.plugin_manager.getPluginsOfCategory("RestExtension"):
- if (plugin_info.name in site.config['DISABLED_PLUGINS']
- or (plugin_info.name in site.EXTRA_PLUGINS and
- plugin_info.name not in site.config['ENABLED_EXTRAS'])):
+ if plugin_info.name in site.config['DISABLED_PLUGINS']:
site.plugin_manager.removePluginFromCategory(plugin_info, "RestExtension")
continue
diff --git a/nikola/plugins/compile/rest/chart.py b/nikola/plugins/compile/rest/chart.py
index 03878a3..55ddf5c 100644
--- a/nikola/plugins/compile/rest/chart.py
+++ b/nikola/plugins/compile/rest/chart.py
@@ -37,13 +37,16 @@ except ImportError:
from nikola.plugin_categories import RestExtension
from nikola.utils import req_missing
+_site = None
+
class Plugin(RestExtension):
name = "rest_chart"
def set_site(self, site):
- self.site = site
+ global _site
+ _site = self.site = site
directives.register_directive('chart', Chart)
return super(Plugin, self).set_site(site)
@@ -146,5 +149,9 @@ class Chart(Directive):
for line in self.content:
label, series = literal_eval('({0})'.format(line))
chart.add(label, series)
-
- return [nodes.raw('', chart.render().decode('utf8'), format='html')]
+ data = chart.render().decode('utf8')
+ if _site and _site.invariant:
+ import re
+ data = re.sub('id="chart-[a-f0-9\-]+"', 'id="chart-foobar"', data)
+ data = re.sub('#chart-[a-f0-9\-]+', '#chart-foobar', data)
+ return [nodes.raw('', data, format='html')]
diff --git a/nikola/plugins/compile/rest/doc.py b/nikola/plugins/compile/rest/doc.py
index a150a81..6143606 100644
--- a/nikola/plugins/compile/rest/doc.py
+++ b/nikola/plugins/compile/rest/doc.py
@@ -48,7 +48,6 @@ def doc_role(name, rawtext, text, lineno, inliner,
# split link's text and post's slug in role content
has_explicit_title, title, slug = split_explicit_title(text)
-
# check if the slug given is part of our blog posts/pages
twin_slugs = False
post = None
@@ -73,7 +72,6 @@ def doc_role(name, rawtext, text, lineno, inliner,
if not has_explicit_title:
# use post's title as link's text
title = post.title()
-
permalink = post.permalink()
if twin_slugs:
msg = inliner.reporter.warning(
diff --git a/nikola/plugins/compile/rest/listing.py b/nikola/plugins/compile/rest/listing.py
index d70e02d..18a1807 100644
--- a/nikola/plugins/compile/rest/listing.py
+++ b/nikola/plugins/compile/rest/listing.py
@@ -46,6 +46,7 @@ except ImportError: # docutils < 0.9 (Debian Sid For The Loss)
class CodeBlock(Directive):
required_arguments = 1
has_content = True
+ option_spec = {}
CODE = '<pre>{0}</pre>'
def run(self):
diff --git a/nikola/plugins/compile/rest/post_list.py b/nikola/plugins/compile/rest/post_list.py
index 6804b58..456e571 100644
--- a/nikola/plugins/compile/rest/post_list.py
+++ b/nikola/plugins/compile/rest/post_list.py
@@ -124,7 +124,10 @@ class PostList(Directive):
show_all = self.options.get('all', False)
lang = self.options.get('lang', utils.LocaleBorg().current_lang)
template = self.options.get('template', 'post_list_directive.tmpl')
- post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex)
+ if self.site.invariant: # for testing purposes
+ post_list_id = self.options.get('id', 'post_list_' + 'fixedvaluethatisnotauuid')
+ else:
+ post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex)
posts = []
step = -1 if reverse is None else None
diff --git a/nikola/plugins/compile/rest/slides.py b/nikola/plugins/compile/rest/slides.py
index 203ae51..ea8e413 100644
--- a/nikola/plugins/compile/rest/slides.py
+++ b/nikola/plugins/compile/rest/slides.py
@@ -53,12 +53,17 @@ class Slides(Directive):
if len(self.content) == 0:
return
+ if self.site.invariant: # for testing purposes
+ carousel_id = 'slides_' + 'fixedvaluethatisnotauuid'
+ else:
+ carousel_id = 'slides_' + uuid.uuid4().hex
+
output = self.site.template_system.render_template(
'slides.tmpl',
None,
{
- 'content': self.content,
- 'carousel_id': 'slides_' + uuid.uuid4().hex,
+ 'slides_content': self.content,
+ 'carousel_id': carousel_id,
}
)
return [nodes.raw('', output, format='html')]
diff --git a/nikola/plugins/compile/rest/vimeo.py b/nikola/plugins/compile/rest/vimeo.py
index 82c4dc1..4b34dfe 100644
--- a/nikola/plugins/compile/rest/vimeo.py
+++ b/nikola/plugins/compile/rest/vimeo.py
@@ -49,9 +49,9 @@ class Plugin(RestExtension):
return super(Plugin, self).set_site(site)
-CODE = """<iframe src="http://player.vimeo.com/video/{vimeo_id}"
+CODE = """<iframe src="//player.vimeo.com/video/{vimeo_id}"
width="{width}" height="{height}"
-frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen>
+frameborder="0" webkitAllowFullScreen="webkitAllowFullScreen" mozallowfullscreen="mozallowfullscreen" allowFullScreen="allowFullScreen">
</iframe>
"""
@@ -108,7 +108,7 @@ class Vimeo(Directive):
if json: # we can attempt to retrieve video attributes from vimeo
try:
- url = ('http://vimeo.com/api/v2/video/{0}'
+ url = ('//vimeo.com/api/v2/video/{0}'
'.json'.format(self.arguments[0]))
data = requests.get(url).text
video_attributes = json.loads(data)[0]
diff --git a/nikola/plugins/compile/rest/youtube.py b/nikola/plugins/compile/rest/youtube.py
index 19e12d1..b32e77a 100644
--- a/nikola/plugins/compile/rest/youtube.py
+++ b/nikola/plugins/compile/rest/youtube.py
@@ -44,7 +44,7 @@ class Plugin(RestExtension):
CODE = """\
<iframe width="{width}"
height="{height}"
-src="http://www.youtube.com/embed/{yid}?rel=0&amp;hd=1&amp;wmode=transparent"
+src="//www.youtube.com/embed/{yid}?rel=0&amp;hd=1&amp;wmode=transparent"
></iframe>"""
diff --git a/nikola/plugins/compile/textile.plugin b/nikola/plugins/compile/textile.plugin
deleted file mode 100644
index 6439b0f..0000000
--- a/nikola/plugins/compile/textile.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = textile
-Module = textile
-
-[Documentation]
-Author = Roberto Alsina
-Version = 0.1
-Website = http://getnikola.com
-Description = Compile Textile into HTML
-
diff --git a/nikola/plugins/compile/textile.py b/nikola/plugins/compile/textile.py
deleted file mode 100644
index 1679831..0000000
--- a/nikola/plugins/compile/textile.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-"""Implementation of compile_html based on textile."""
-
-import codecs
-import os
-import re
-
-try:
- from textile import textile
-except ImportError:
- textile = None # NOQA
-
-from nikola.plugin_categories import PageCompiler
-from nikola.utils import makedirs, req_missing
-
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
-
-
-class CompileTextile(PageCompiler):
- """Compile textile into HTML."""
-
- name = "textile"
- demote_headers = True
-
- def compile_html(self, source, dest, is_two_file=True):
- if textile is None:
- req_missing(['textile'], 'build this site (compile Textile)')
- makedirs(os.path.dirname(dest))
- with codecs.open(dest, "w+", "utf8") as out_file:
- with codecs.open(source, "r", "utf8") as in_file:
- data = in_file.read()
- if not is_two_file:
- data = re.split('(\n\n|\r\n\r\n)', data, maxsplit=1)[-1]
- output = textile(data, head_offset=1)
- out_file.write(output)
-
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
- metadata.update(self.default_metadata)
- metadata.update(kw)
- makedirs(os.path.dirname(path))
- with codecs.open(path, "wb+", "utf8") as fd:
- if onefile:
- fd.write('<notextile> <!--\n')
- for k, v in metadata.items():
- fd.write('.. {0}: {1}\n'.format(k, v))
- fd.write('--></notextile>\n\n')
- fd.write("\nWrite your {0} here.".format('page' if is_page else 'post'))
diff --git a/nikola/plugins/compile/txt2tags.plugin b/nikola/plugins/compile/txt2tags.plugin
deleted file mode 100644
index 55eb0a0..0000000
--- a/nikola/plugins/compile/txt2tags.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = txt2tags
-Module = txt2tags
-
-[Documentation]
-Author = Roberto Alsina
-Version = 0.1
-Website = http://getnikola.com
-Description = Compile Txt2tags into HTML
-
diff --git a/nikola/plugins/compile/txt2tags.py b/nikola/plugins/compile/txt2tags.py
deleted file mode 100644
index bb6afa5..0000000
--- a/nikola/plugins/compile/txt2tags.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-"""Implementation of compile_html based on txt2tags.
-
-Txt2tags is not in PyPI, you can install it with
-
-easy_install -f "http://txt2tags.org/txt2tags.py#egg=txt2tags-2.6" txt2tags
-
-"""
-
-import codecs
-import os
-
-try:
- from txt2tags import exec_command_line as txt2tags
-except ImportError:
- txt2tags = None # NOQA
-
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
-
-from nikola.plugin_categories import PageCompiler
-from nikola.utils import makedirs, req_missing
-
-
-class CompileTxt2tags(PageCompiler):
- """Compile txt2tags into HTML."""
-
- name = "txt2tags"
- demote_headers = True
-
- def compile_html(self, source, dest, is_two_file=True):
- if txt2tags is None:
- req_missing(['txt2tags'], 'build this site (compile txt2tags)')
- makedirs(os.path.dirname(dest))
- cmd = ["-t", "html", "--no-headers", "--outfile", dest, source]
- txt2tags(cmd)
-
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
- metadata.update(self.default_metadata)
- metadata.update(kw)
- makedirs(os.path.dirname(path))
- with codecs.open(path, "wb+", "utf8") as fd:
- if onefile:
- fd.write("\n'''\n<!--\n")
- for k, v in metadata.items():
- fd.write('.. {0}: {1}\n'.format(k, v))
- fd.write("-->\n'''\n")
- fd.write("\nWrite your {0} here.".format('page' if is_page else 'post'))
diff --git a/nikola/plugins/compile/wiki.plugin b/nikola/plugins/compile/wiki.plugin
deleted file mode 100644
index eee14a8..0000000
--- a/nikola/plugins/compile/wiki.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = wiki
-Module = wiki
-
-[Documentation]
-Author = Roberto Alsina
-Version = 0.1
-Website = http://getnikola.com
-Description = Compile WikiMarkup into HTML
-
diff --git a/nikola/plugins/compile/wiki.py b/nikola/plugins/compile/wiki.py
deleted file mode 100644
index f4858c7..0000000
--- a/nikola/plugins/compile/wiki.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-"""Implementation of compile_html based on CreoleWiki."""
-
-import codecs
-import os
-
-try:
- from creole import Parser
- from creole.html_emitter import HtmlEmitter
- creole = True
-except ImportError:
- creole = None
-
-from nikola.plugin_categories import PageCompiler
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict # NOQA
-
-from nikola.utils import makedirs, req_missing
-
-
-class CompileWiki(PageCompiler):
- """Compile CreoleWiki into HTML."""
-
- name = "wiki"
- demote_headers = True
-
- def compile_html(self, source, dest, is_two_file=True):
- if creole is None:
- req_missing(['creole'], 'build this site (compile CreoleWiki)')
- makedirs(os.path.dirname(dest))
- with codecs.open(dest, "w+", "utf8") as out_file:
- with codecs.open(source, "r", "utf8") as in_file:
- data = in_file.read()
- document = Parser(data).parse()
- output = HtmlEmitter(document).emit()
- out_file.write(output)
-
- def create_post(self, path, onefile=False, is_page=False, **kw):
- metadata = OrderedDict()
- metadata.update(self.default_metadata)
- metadata.update(kw)
- makedirs(os.path.dirname(path))
- if onefile:
- raise Exception('There are no comments in CreoleWiki markup, so '
- 'one-file format is not possible, use the -2 '
- 'option.')
- with codecs.open(path, "wb+", "utf8") as fd:
- fd.write("Write your {0} here.".format('page' if is_page else 'post'))
diff --git a/nikola/plugins/loghandler/stderr.py b/nikola/plugins/loghandler/stderr.py
index fdc892e..593c381 100644
--- a/nikola/plugins/loghandler/stderr.py
+++ b/nikola/plugins/loghandler/stderr.py
@@ -41,7 +41,11 @@ class StderrHandler(SignalHandler):
conf = self.site.config.get('LOGGING_HANDLERS').get('stderr')
if conf or os.getenv('NIKOLA_DEBUG'):
self.site.loghandlers.append(ColorfulStderrHandler(
- level='DEBUG' if DEBUG else conf.get('loglevel', 'WARNING').upper(),
+ # We do not allow the level to be something else than 'DEBUG'
+ # or 'INFO' Any other level can have bad effects on the user
+ # experience and is discouraged.
+ # (oh, and it was incorrectly set to WARNING before)
+ level='DEBUG' if DEBUG or (conf.get('loglevel', 'INFO').upper() == 'DEBUG') else 'INFO',
format_string=u'[{record.time:%Y-%m-%dT%H:%M:%SZ}] {record.level_name}: {record.channel}: {record.message}'
))
diff --git a/nikola/plugins/task/archive.py b/nikola/plugins/task/archive.py
index a65a63f..4f1ab19 100644
--- a/nikola/plugins/task/archive.py
+++ b/nikola/plugins/task/archive.py
@@ -73,16 +73,15 @@ class Archive(Task):
context["permalink"] = self.site.link("archive", year, lang)
if not kw["create_monthly_archive"]:
template_name = "list_post.tmpl"
- post_list = [self.site.global_data[post] for post in posts]
- post_list.sort(key=lambda a: a.date)
+ post_list = sorted(posts, key=lambda a: a.date)
post_list.reverse()
context["posts"] = post_list
else: # Monthly archives, just list the months
- months = set([m.split('/')[1] for m in self.site.posts_per_month.keys() if m.startswith(str(year))])
+ months = set([(m.split('/')[1], self.site.link("archive", m, lang)) for m in self.site.posts_per_month.keys() if m.startswith(str(year))])
months = sorted(list(months))
months.reverse()
template_name = "list.tmpl"
- context["items"] = [[nikola.utils.LocaleBorg().get_month_name(int(month), lang), month] for month in months]
+ context["items"] = [[nikola.utils.LocaleBorg().get_month_name(int(month), lang), link] for month, link in months]
post_list = []
task = self.site.generic_post_list_renderer(
lang,
@@ -93,7 +92,12 @@ class Archive(Task):
context,
)
n = len(post_list) if 'posts' in context else len(months)
- task_cfg = {1: task['uptodate'][0].config, 2: kw, 3: n}
+
+ deps_translatable = {}
+ for k in self.site._GLOBAL_CONTEXT_TRANSLATABLE:
+ deps_translatable[k] = self.site.GLOBAL_CONTEXT[k](lang)
+
+ task_cfg = {1: task['uptodate'][0].config, 2: kw, 3: n, 4: deps_translatable}
task['uptodate'] = [config_changed(task_cfg)]
task['basename'] = self.name
yield task
@@ -106,8 +110,7 @@ class Archive(Task):
kw['output_folder'], self.site.path("archive", yearmonth,
lang))
year, month = yearmonth.split('/')
- post_list = [self.site.global_data[post] for post in posts]
- post_list.sort(key=lambda a: a.date)
+ post_list = sorted(posts, key=lambda a: a.date)
post_list.reverse()
context = {}
context["lang"] = lang
@@ -141,8 +144,8 @@ class Archive(Task):
kw['output_folder'], self.site.path("archive", None,
lang))
context["title"] = kw["messages"][lang]["Archive"]
- context["items"] = [(year, self.site.link("archive", year, lang))
- for year in years]
+ context["items"] = [(y, self.site.link("archive", y, lang))
+ for y in years]
context["permalink"] = self.site.link("archive", None, lang)
task = self.site.generic_post_list_renderer(
lang,
diff --git a/nikola/plugins/task/build_less.plugin b/nikola/plugins/task/build_less.plugin
deleted file mode 100644
index 27ca8cd..0000000
--- a/nikola/plugins/task/build_less.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = build_less
-Module = build_less
-
-[Documentation]
-Author = Roberto Alsina
-Version = 0.1
-Website = http://getnikola.com
-Description = Build CSS out of LESS sources
-
diff --git a/nikola/plugins/task/build_less.py b/nikola/plugins/task/build_less.py
deleted file mode 100644
index a672282..0000000
--- a/nikola/plugins/task/build_less.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-from __future__ import unicode_literals
-
-import codecs
-import glob
-import os
-import sys
-import subprocess
-
-from nikola.plugin_categories import Task
-from nikola import utils
-
-
-class BuildLess(Task):
- """Generate CSS out of LESS sources."""
-
- name = "build_less"
- sources_folder = "less"
- sources_ext = ".less"
-
- def gen_tasks(self):
- """Generate CSS out of LESS sources."""
- self.compiler_name = self.site.config['LESS_COMPILER']
- self.compiler_options = self.site.config['LESS_OPTIONS']
-
- kw = {
- 'cache_folder': self.site.config['CACHE_FOLDER'],
- 'themes': self.site.THEMES,
- }
- tasks = {}
-
- # Find where in the theme chain we define the LESS targets
- # There can be many *.less in the folder, but we only will build
- # the ones listed in less/targets
- if os.path.isfile(os.path.join(self.sources_folder, "targets")):
- targets_path = os.path.join(self.sources_folder, "targets")
- else:
- targets_path = utils.get_asset_path(os.path.join(self.sources_folder, "targets"), self.site.THEMES)
- try:
- with codecs.open(targets_path, "rb", "utf-8") as inf:
- targets = [x.strip() for x in inf.readlines()]
- except Exception:
- targets = []
-
- for task in utils.copy_tree(self.sources_folder, os.path.join(kw['cache_folder'], self.sources_folder)):
- if task['name'] in tasks:
- continue
- task['basename'] = 'prepare_less_sources'
- tasks[task['name']] = task
- yield task
-
- for theme_name in kw['themes']:
- src = os.path.join(utils.get_theme_path(theme_name), self.sources_folder)
- for task in utils.copy_tree(src, os.path.join(kw['cache_folder'], self.sources_folder)):
- task['basename'] = 'prepare_less_sources'
- yield task
-
- # Build targets and write CSS files
- base_path = utils.get_theme_path(self.site.THEMES[0])
- dst_dir = os.path.join(self.site.config['OUTPUT_FOLDER'], 'assets', 'css')
- # Make everything depend on all sources, rough but enough
- deps = glob.glob(os.path.join(
- base_path,
- self.sources_folder,
- "*{0}".format(self.sources_ext)))
-
- def compile_target(target, dst):
- utils.makedirs(dst_dir)
- src = os.path.join(kw['cache_folder'], self.sources_folder, target)
- run_in_shell = sys.platform == 'win32'
- try:
- compiled = subprocess.check_output([self.compiler_name] + self.compiler_options + [src], shell=run_in_shell)
- except OSError:
- utils.req_missing([self.compiler_name],
- 'build LESS files (and use this theme)',
- False, False)
- with open(dst, "wb+") as outf:
- outf.write(compiled)
-
- yield self.group_task()
-
- for target in targets:
- dst = os.path.join(dst_dir, target.replace(self.sources_ext, ".css"))
- yield {
- 'basename': self.name,
- 'name': dst,
- 'targets': [dst],
- 'file_dep': deps,
- 'task_dep': ['prepare_less_sources'],
- 'actions': ((compile_target, [target, dst]), ),
- 'uptodate': [utils.config_changed(kw)],
- 'clean': True
- }
diff --git a/nikola/plugins/task/build_sass.plugin b/nikola/plugins/task/build_sass.plugin
deleted file mode 100644
index 746c1df..0000000
--- a/nikola/plugins/task/build_sass.plugin
+++ /dev/null
@@ -1,9 +0,0 @@
-[Core]
-Name = build_sass
-Module = build_sass
-
-[Documentation]
-Author = Roberto Alsina, Chris “Kwpolska” Warrick
-Version = 0.1
-Website = http://getnikola.com
-Description = Build CSS out of Sass sources
diff --git a/nikola/plugins/task/build_sass.py b/nikola/plugins/task/build_sass.py
deleted file mode 100644
index becc843..0000000
--- a/nikola/plugins/task/build_sass.py
+++ /dev/null
@@ -1,139 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-from __future__ import unicode_literals
-
-import codecs
-import glob
-import os
-import sys
-import subprocess
-
-from nikola.plugin_categories import Task
-from nikola import utils
-
-
-class BuildSass(Task):
- """Generate CSS out of Sass sources."""
-
- name = "build_sass"
- sources_folder = "sass"
- sources_ext = (".sass", ".scss")
-
- def gen_tasks(self):
- """Generate CSS out of Sass sources."""
- self.logger = utils.get_logger('build_sass', self.site.loghandlers)
- self.compiler_name = self.site.config['SASS_COMPILER']
- self.compiler_options = self.site.config['SASS_OPTIONS']
-
- kw = {
- 'cache_folder': self.site.config['CACHE_FOLDER'],
- 'themes': self.site.THEMES,
- }
- tasks = {}
-
- # Find where in the theme chain we define the Sass targets
- # There can be many *.sass/*.scss in the folder, but we only
- # will build the ones listed in sass/targets
- if os.path.isfile(os.path.join(self.sources_folder, "targets")):
- targets_path = os.path.join(self.sources_folder, "targets")
- else:
- targets_path = utils.get_asset_path(os.path.join(self.sources_folder, "targets"), self.site.THEMES)
- try:
- with codecs.open(targets_path, "rb", "utf-8") as inf:
- targets = [x.strip() for x in inf.readlines()]
- except Exception:
- targets = []
-
- for task in utils.copy_tree(self.sources_folder, os.path.join(kw['cache_folder'], self.sources_folder)):
- if task['name'] in tasks:
- continue
- task['basename'] = 'prepare_sass_sources'
- tasks[task['name']] = task
- yield task
-
- for theme_name in kw['themes']:
- src = os.path.join(utils.get_theme_path(theme_name), self.sources_folder)
- for task in utils.copy_tree(src, os.path.join(kw['cache_folder'], self.sources_folder)):
- if task['name'] in tasks:
- continue
- task['basename'] = 'prepare_sass_sources'
- tasks[task['name']] = task
- yield task
-
- # Build targets and write CSS files
- base_path = utils.get_theme_path(self.site.THEMES[0])
- dst_dir = os.path.join(self.site.config['OUTPUT_FOLDER'], 'assets', 'css')
- # Make everything depend on all sources, rough but enough
- deps = glob.glob(os.path.join(
- base_path,
- self.sources_folder,
- *("*{0}".format(ext) for ext in self.sources_ext)))
-
- def compile_target(target, dst):
- utils.makedirs(dst_dir)
- run_in_shell = sys.platform == 'win32'
- src = os.path.join(kw['cache_folder'], self.sources_folder, target)
- try:
- compiled = subprocess.check_output([self.compiler_name] + self.compiler_options + [src], shell=run_in_shell)
- except OSError:
- utils.req_missing([self.compiler_name],
- 'build Sass files (and use this theme)',
- False, False)
- with open(dst, "wb+") as outf:
- outf.write(compiled)
-
- yield self.group_task()
-
- # We can have file conflicts. This is a way to prevent them.
- # I orignally wanted to use sets and their cannot-have-duplicates
- # magic, but I decided not to do this so we can show the user
- # what files were problematic.
- # If we didn’t do this, there would be a cryptic message from doit
- # instead.
- seennames = {}
- for target in targets:
- base = os.path.splitext(target)[0]
- dst = os.path.join(dst_dir, base + ".css")
-
- if base in seennames:
- self.logger.error(
- 'Duplicate filenames for Sass compiled files: {0} and '
- '{1} (both compile to {2})'.format(
- seennames[base], target, base + ".css"))
- else:
- seennames.update({base: target})
-
- yield {
- 'basename': self.name,
- 'name': dst,
- 'targets': [dst],
- 'file_dep': deps,
- 'task_dep': ['prepare_sass_sources'],
- 'actions': ((compile_target, [target, dst]), ),
- 'uptodate': [utils.config_changed(kw)],
- 'clean': True
- }
diff --git a/nikola/plugins/task/bundles.py b/nikola/plugins/task/bundles.py
index fcfaf42..7437a9d 100644
--- a/nikola/plugins/task/bundles.py
+++ b/nikola/plugins/task/bundles.py
@@ -65,8 +65,7 @@ class BuildBundles(LateTask):
def build_bundle(output, inputs):
out_dir = os.path.join(kw['output_folder'],
os.path.dirname(output))
- inputs = [i for i in inputs if os.path.isfile(
- os.path.join(out_dir, i))]
+ inputs = [os.path.relpath(i, out_dir) for i in inputs if os.path.isfile(i)]
cache_dir = os.path.join(kw['cache_folder'], 'webassets')
utils.makedirs(cache_dir)
env = webassets.Environment(out_dir, os.path.dirname(output),
@@ -83,20 +82,32 @@ class BuildBundles(LateTask):
yield self.group_task()
if (webassets is not None and self.site.config['USE_BUNDLES'] is not
False):
- for name, files in kw['theme_bundles'].items():
+ for name, _files in kw['theme_bundles'].items():
output_path = os.path.join(kw['output_folder'], name)
dname = os.path.dirname(name)
- file_dep = [os.path.join(kw['output_folder'], dname, fname)
+ files = []
+ for fname in _files:
+ # paths are relative to dirname
+ files.append(os.path.join(dname, fname))
+ file_dep = [os.path.join(kw['output_folder'], fname)
for fname in files if
- utils.get_asset_path(fname, self.site.THEMES, self.site.config['FILES_FOLDERS'])]
+ utils.get_asset_path(fname, self.site.THEMES, self.site.config['FILES_FOLDERS'])
+ or fname == 'assets/css/code.css']
+ # code.css will be generated by us if it does not exist in
+ # FILES_FOLDERS or theme assets. It is guaranteed that the
+ # generation will happen before this task.
task = {
'file_dep': list(file_dep),
- 'task_dep': ['copy_assets'],
+ 'task_dep': ['copy_assets', 'copy_files'],
'basename': str(self.name),
'name': str(output_path),
- 'actions': [(build_bundle, (name, files))],
+ 'actions': [(build_bundle, (name, file_dep))],
'targets': [output_path],
- 'uptodate': [utils.config_changed(kw)],
+ 'uptodate': [
+ utils.config_changed({
+ 1: kw,
+ 2: file_dep
+ })],
'clean': True,
}
yield utils.apply_filters(task, kw['filters'])
diff --git a/nikola/plugins/task/copy_assets.py b/nikola/plugins/task/copy_assets.py
index 93b7fb3..4801347 100644
--- a/nikola/plugins/task/copy_assets.py
+++ b/nikola/plugins/task/copy_assets.py
@@ -45,13 +45,21 @@ class CopyAssets(Task):
kw = {
"themes": self.site.THEMES,
+ "files_folders": self.site.config['FILES_FOLDERS'],
"output_folder": self.site.config['OUTPUT_FOLDER'],
"filters": self.site.config['FILTERS'],
"code_color_scheme": self.site.config['CODE_COLOR_SCHEME'],
+ "code.css_selectors": 'pre.code',
+ "code.css_head": '/* code.css file generated by Nikola */\n',
+ "code.css_close": "\ntable.codetable { width: 100%;} td.linenos {text-align: right; width: 4em;}\n",
}
- has_code_css = False
tasks = {}
code_css_path = os.path.join(kw['output_folder'], 'assets', 'css', 'code.css')
+ code_css_input = utils.get_asset_path('assets/css/code.css',
+ themes=kw['themes'],
+ files_folders=kw['files_folders'])
+
+ kw["code.css_input"] = code_css_input
yield self.group_task()
@@ -61,28 +69,35 @@ class CopyAssets(Task):
for task in utils.copy_tree(src, dst):
if task['name'] in tasks:
continue
- if task['targets'][0] == code_css_path:
- has_code_css = True
tasks[task['name']] = task
task['uptodate'] = [utils.config_changed(kw)]
task['basename'] = self.name
+ if code_css_input:
+ task['file_dep'] = [code_css_input]
yield utils.apply_filters(task, kw['filters'])
- if not has_code_css: # Generate it
-
+ # Check whether or not there is a code.css file around.
+ if not code_css_input:
def create_code_css():
from pygments.formatters import get_formatter_by_name
formatter = get_formatter_by_name('html', style=kw["code_color_scheme"])
utils.makedirs(os.path.dirname(code_css_path))
with codecs.open(code_css_path, 'wb+', 'utf8') as outf:
- outf.write(formatter.get_style_defs(['pre.code', 'div.code pre']))
- outf.write("\ntable.codetable { width: 100%;} td.linenos {text-align: right; width: 4em;}\n")
+ outf.write(kw["code.css_head"])
+ outf.write(formatter.get_style_defs(kw["code.css_selectors"]))
+ outf.write(kw["code.css_close"])
+
+ if os.path.exists(code_css_path):
+ with codecs.open(code_css_path, 'r', 'utf-8') as fh:
+ testcontents = fh.read(len(kw["code.css_head"])) == kw["code.css_head"]
+ else:
+ testcontents = False
task = {
'basename': self.name,
'name': code_css_path,
'targets': [code_css_path],
- 'uptodate': [utils.config_changed(kw)],
+ 'uptodate': [utils.config_changed(kw), testcontents],
'actions': [(create_code_css, [])],
'clean': True,
}
diff --git a/nikola/plugins/task/galleries.py b/nikola/plugins/task/galleries.py
index 880d47c..366374b 100644
--- a/nikola/plugins/task/galleries.py
+++ b/nikola/plugins/task/galleries.py
@@ -36,6 +36,7 @@ try:
except ImportError:
from urllib.parse import urljoin # NOQA
+import natsort
Image = None
try:
from PIL import Image, ExifTags # NOQA
@@ -46,6 +47,7 @@ except ImportError:
Image = _Image
except ImportError:
pass
+
import PyRSS2Gen as rss
from nikola.plugin_categories import Task
@@ -97,9 +99,15 @@ class Galleries(Task):
'filters': self.site.config['FILTERS'],
'translations': self.site.config['TRANSLATIONS'],
'global_context': self.site.GLOBAL_CONTEXT,
- "feed_length": self.site.config['FEED_LENGTH'],
+ 'feed_length': self.site.config['FEED_LENGTH'],
+ 'tzinfo': self.site.tzinfo,
+ 'comments_in_galleries': self.site.config['COMMENTS_IN_GALLERIES'],
+ 'generate_rss': self.site.config['GENERATE_RSS'],
}
+ for k, v in self.site.GLOBAL_CONTEXT['template_hooks'].items():
+ self.kw['||template_hooks|{0}||'.format(k)] = v._items
+
yield self.group_task()
template_name = "gallery.tmpl"
@@ -152,6 +160,9 @@ class Galleries(Task):
os.path.relpath(gallery, self.kw['gallery_path']), lang))
dst = os.path.normpath(dst)
+ for k in self.site._GLOBAL_CONTEXT_TRANSLATABLE:
+ self.kw[k] = self.site.GLOBAL_CONTEXT[k](lang)
+
context = {}
context["lang"] = lang
if post:
@@ -165,12 +176,8 @@ class Galleries(Task):
if self.kw['use_filename_as_title']:
img_titles = []
for fn in image_name_list:
- name_without_ext = os.path.splitext(fn)[0]
- img_titles.append(
- 'id="{0}" alt="{1}" title="{2}"'.format(
- name_without_ext,
- name_without_ext,
- utils.unslugify(name_without_ext)))
+ name_without_ext = os.path.splitext(os.path.basename(fn))[0]
+ img_titles.append(utils.unslugify(name_without_ext))
else:
img_titles = [''] * len(image_name_list)
@@ -189,27 +196,30 @@ class Galleries(Task):
ft = folder
folders.append((folder, ft))
- ## TODO: in v7 remove images from context, use photo_array
- context["images"] = list(zip(image_name_list, thumbs, img_titles))
- context["folders"] = folders
+ context["folders"] = natsort.natsorted(folders)
context["crumbs"] = crumbs
context["permalink"] = self.site.link(
"gallery", os.path.basename(
os.path.relpath(gallery, self.kw['gallery_path'])), lang)
- # FIXME: use kw
- context["enable_comments"] = (
- self.site.config["COMMENTS_IN_GALLERIES"])
+ context["enable_comments"] = self.kw['comments_in_galleries']
context["thumbnail_size"] = self.kw["thumbnail_size"]
- # FIXME: render post in a task
if post:
- post.compile(lang)
- context['text'] = post.text(lang)
+ yield {
+ 'basename': self.name,
+ 'name': post.translated_base_path(lang),
+ 'targets': [post.translated_base_path(lang)],
+ 'file_dep': post.fragment_deps(lang),
+ 'actions': [(post.compile, [lang])],
+ 'uptodate': [utils.config_changed(self.kw)]
+ }
+ context['post'] = post
else:
- context['text'] = ''
-
+ context['post'] = None
file_dep = self.site.template_system.template_deps(
template_name) + image_list + thumbs
+ if post:
+ file_dep += [post.translated_base_path(l) for l in self.kw['translations']]
yield utils.apply_filters({
'basename': self.name,
@@ -222,6 +232,7 @@ class Galleries(Task):
dst,
context,
dest_img_list,
+ img_titles,
thumbs,
file_dep))],
'clean': True,
@@ -233,39 +244,40 @@ class Galleries(Task):
}, self.kw['filters'])
# RSS for the gallery
- rss_dst = os.path.join(
- self.kw['output_folder'],
- self.site.path(
- "gallery_rss",
- os.path.relpath(gallery, self.kw['gallery_path']), lang))
- rss_dst = os.path.normpath(rss_dst)
-
- yield utils.apply_filters({
- 'basename': self.name,
- 'name': rss_dst,
- 'file_dep': file_dep,
- 'targets': [rss_dst],
- 'actions': [
- (self.gallery_rss, (
- image_list,
- img_titles,
- lang,
- self.site.link(
- "gallery_rss", os.path.basename(gallery), lang),
- rss_dst,
- context['title']
- ))],
- 'clean': True,
- 'uptodate': [utils.config_changed({
- 1: self.kw,
- })],
- }, self.kw['filters'])
+ if self.kw["generate_rss"]:
+ rss_dst = os.path.join(
+ self.kw['output_folder'],
+ self.site.path(
+ "gallery_rss",
+ os.path.relpath(gallery, self.kw['gallery_path']), lang))
+ rss_dst = os.path.normpath(rss_dst)
+
+ yield utils.apply_filters({
+ 'basename': self.name,
+ 'name': rss_dst,
+ 'file_dep': file_dep,
+ 'targets': [rss_dst],
+ 'actions': [
+ (self.gallery_rss, (
+ image_list,
+ img_titles,
+ lang,
+ self.site.link(
+ "gallery_rss", os.path.basename(gallery), lang),
+ rss_dst,
+ context['title']
+ ))],
+ 'clean': True,
+ 'uptodate': [utils.config_changed({
+ 1: self.kw,
+ })],
+ }, self.kw['filters'])
def find_galleries(self):
"""Find all galleries to be processed according to conf.py"""
self.gallery_list = []
- for root, dirs, files in os.walk(self.kw['gallery_path']):
+ for root, dirs, files in os.walk(self.kw['gallery_path'], followlinks=True):
self.gallery_list.append(root)
def create_galleries(self):
@@ -433,6 +445,7 @@ class Galleries(Task):
output_name,
context,
img_list,
+ img_titles,
thumbs,
file_dep):
"""Build the gallery index."""
@@ -446,12 +459,9 @@ class Galleries(Task):
return url
photo_array = []
- for img, thumb in zip(img_list, thumbs):
+ for img, thumb, title in zip(img_list, thumbs, img_titles):
im = Image.open(thumb)
w, h = im.size
- title = ''
- if self.kw['use_filename_as_title']:
- title = utils.unslugify(os.path.splitext(img)[0])
# Thumbs are files in output, we need URLs
photo_array.append({
'url': url_from_path(img),
@@ -462,9 +472,8 @@ class Galleries(Task):
'h': h
},
})
- context['photo_array_json'] = json.dumps(photo_array)
context['photo_array'] = photo_array
-
+ context['photo_array_json'] = json.dumps(photo_array)
self.site.render_template(template_name, output_name, context)
def gallery_rss(self, img_list, img_titles, lang, permalink, output_path, title):
@@ -478,12 +487,12 @@ class Galleries(Task):
return urljoin(self.site.config['BASE_URL'], url)
items = []
- for img, full_title in list(zip(img_list, img_titles))[:self.kw["feed_length"]]:
+ for img, title in list(zip(img_list, img_titles))[:self.kw["feed_length"]]:
img_size = os.stat(
os.path.join(
self.site.config['OUTPUT_FOLDER'], img)).st_size
args = {
- 'title': full_title.split('"')[-2] if full_title else '',
+ 'title': title,
'link': make_url(img),
'guid': rss.Guid(img, False),
'pubDate': self.image_date(img),
@@ -494,17 +503,16 @@ class Galleries(Task):
),
}
items.append(rss.RSSItem(**args))
- rss_obj = utils.ExtendedRSS2(
+ rss_obj = rss.RSS2(
title=title,
link=make_url(permalink),
description='',
lastBuildDate=datetime.datetime.now(),
items=items,
- generator='Nikola <http://getnikola.com/>',
+ generator='http://getnikola.com/',
language=lang
)
- rss_obj.self_url = make_url(permalink)
- rss_obj.rss_attrs["xmlns:atom"] = "http://www.w3.org/2005/Atom"
+ rss_obj.rss_attrs["xmlns:dc"] = "http://purl.org/dc/elements/1.1/"
dst_dir = os.path.dirname(output_path)
utils.makedirs(dst_dir)
with codecs.open(output_path, "wb+", "utf-8") as rss_file:
@@ -564,7 +572,7 @@ class Galleries(Task):
if exif is not None:
for tag, value in list(exif.items()):
decoded = ExifTags.TAGS.get(tag, tag)
- if decoded == 'DateTimeOriginal':
+ if decoded in ('DateTimeOriginal', 'DateTimeDigitized'):
try:
self.dates[src] = datetime.datetime.strptime(
value, r'%Y:%m:%d %H:%M:%S')
diff --git a/nikola/plugins/task/indexes.py b/nikola/plugins/task/indexes.py
index 3f45161..386cc18 100644
--- a/nikola/plugins/task/indexes.py
+++ b/nikola/plugins/task/indexes.py
@@ -25,8 +25,7 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import unicode_literals
-import glob
-import itertools
+from collections import defaultdict
import os
from nikola.plugin_categories import Task
@@ -54,22 +53,23 @@ class Indexes(Task):
"index_teasers": self.site.config['INDEX_TEASERS'],
"output_folder": self.site.config['OUTPUT_FOLDER'],
"filters": self.site.config['FILTERS'],
- "hide_untranslated_posts": self.site.config['HIDE_UNTRANSLATED_POSTS'],
+ "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
"indexes_title": self.site.config['INDEXES_TITLE'],
"indexes_pages": self.site.config['INDEXES_PAGES'],
"indexes_pages_main": self.site.config['INDEXES_PAGES_MAIN'],
"blog_title": self.site.config["BLOG_TITLE"],
+ "rss_read_more_link": self.site.config["RSS_READ_MORE_LINK"],
}
template_name = "index.tmpl"
- posts = [x for x in self.site.timeline if x.use_in_feeds]
+ posts = self.site.posts
for lang in kw["translations"]:
# Split in smaller lists
lists = []
- if kw["hide_untranslated_posts"]:
- filtered_posts = [x for x in posts if x.is_translation_available(lang)]
- else:
+ if kw["show_untranslated_posts"]:
filtered_posts = posts
+ else:
+ filtered_posts = [x for x in posts if x.is_translation_available(lang)]
lists.append(filtered_posts[:kw["index_display_post_count"]])
filtered_posts = filtered_posts[kw["index_display_post_count"]:]
while filtered_posts:
@@ -78,7 +78,7 @@ class Indexes(Task):
num_pages = len(lists)
for i, post_list in enumerate(lists):
context = {}
- indexes_title = kw['indexes_title'] or kw['blog_title']
+ indexes_title = kw['indexes_title'] or kw['blog_title'](lang)
if kw["indexes_pages_main"]:
ipages_i = i + 1
ipages_msg = "page %d"
@@ -134,33 +134,33 @@ class Indexes(Task):
"post_pages": self.site.config["post_pages"],
"output_folder": self.site.config['OUTPUT_FOLDER'],
"filters": self.site.config['FILTERS'],
+ "index_file": self.site.config['INDEX_FILE'],
}
template_name = "list.tmpl"
for lang in kw["translations"]:
# Need to group by folder to avoid duplicated tasks (Issue #758)
- for dirname, wildcards in itertools.groupby((w for w, d, x, i in kw["post_pages"] if not i), os.path.dirname):
- context = {}
- # vim/pyflakes thinks it's unused
- # src_dir = os.path.dirname(wildcard)
- files = []
- for wildcard in wildcards:
- files += glob.glob(wildcard)
- post_list = [self.site.global_data[p] for p in files]
- output_name = os.path.join(kw["output_folder"],
- self.site.path("post_path",
- wildcard,
- lang)).encode('utf8')
- context["items"] = [(post.title(lang), post.permalink(lang))
- for post in post_list]
- task = self.site.generic_post_list_renderer(lang, post_list,
- output_name,
- template_name,
- kw['filters'],
- context)
- task_cfg = {1: task['uptodate'][0].config, 2: kw}
- task['uptodate'] = [config_changed(task_cfg)]
- task['basename'] = self.name
- yield task
+ # Group all pages by path prefix
+ groups = defaultdict(list)
+ for p in self.site.timeline:
+ if not p.is_post:
+ dirname = os.path.dirname(p.destination_path(lang))
+ groups[dirname].append(p)
+ for dirname, post_list in groups.items():
+ context = {}
+ context["items"] = [
+ (post.title(lang), post.permalink(lang))
+ for post in post_list
+ ]
+ output_name = os.path.join(kw['output_folder'], dirname, kw['index_file'])
+ task = self.site.generic_post_list_renderer(lang, post_list,
+ output_name,
+ template_name,
+ kw['filters'],
+ context)
+ task_cfg = {1: task['uptodate'][0].config, 2: kw}
+ task['uptodate'] = [config_changed(task_cfg)]
+ task['basename'] = self.name
+ yield task
def index_path(self, name, lang):
if name not in [None, 0]:
diff --git a/nikola/plugins/task/listings.py b/nikola/plugins/task/listings.py
index 86be6c4..a0fe974 100644
--- a/nikola/plugins/task/listings.py
+++ b/nikola/plugins/task/listings.py
@@ -31,11 +31,17 @@ import os
from pygments import highlight
from pygments.lexers import get_lexer_for_filename, TextLexer
from pygments.formatters import HtmlFormatter
+import natsort
+import re
from nikola.plugin_categories import Task
from nikola import utils
+# FIXME: (almost) duplicated with mdx_nikola.py
+CODERE = re.compile('<div class="code"><pre>(.*?)</pre></div>', flags=re.MULTILINE | re.DOTALL)
+
+
class Listings(Task):
"""Render pretty listings."""
@@ -69,6 +75,9 @@ class Listings(Task):
linenos="table", nowrap=False,
lineanchors=utils.slugify(in_name),
anchorlinenos=True))
+ # the pygments highlighter uses <div class="codehilite"><pre>
+ # for code. We switch it to reST's <pre class="code">.
+ code = CODERE.sub('<pre class="code literal-block">\\1</pre>', code)
title = os.path.basename(in_name)
else:
code = ''
@@ -76,14 +85,27 @@ class Listings(Task):
crumbs = utils.get_crumbs(os.path.relpath(out_name,
kw['output_folder']),
is_file=True)
+ permalink = self.site.link(
+ 'listing',
+ os.path.relpath(
+ out_name,
+ os.path.join(
+ kw['output_folder'],
+ kw['listings_folder'])))
+ if self.site.config['COPY_SOURCES']:
+ source_link = permalink[:-5]
+ else:
+ source_link = None
context = {
'code': code,
'title': title,
'crumbs': crumbs,
+ 'permalink': permalink,
'lang': kw['default_lang'],
- 'folders': folders,
- 'files': files,
+ 'folders': natsort.natsorted(folders),
+ 'files': natsort.natsorted(files),
'description': title,
+ 'source_link': source_link,
}
self.site.render_template('listing.tmpl', out_name,
context)
@@ -91,7 +113,21 @@ class Listings(Task):
yield self.group_task()
template_deps = self.site.template_system.template_deps('listing.tmpl')
- for root, dirs, files in os.walk(kw['listings_folder']):
+ for root, dirs, files in os.walk(kw['listings_folder'], followlinks=True):
+ files = [f for f in files if os.path.splitext(f)[-1] not in ignored_extensions]
+
+ uptodate = {'c': self.site.GLOBAL_CONTEXT}
+
+ for k, v in self.site.GLOBAL_CONTEXT['template_hooks'].items():
+ uptodate['||template_hooks|{0}||'.format(k)] = v._items
+
+ for k in self.site._GLOBAL_CONTEXT_TRANSLATABLE:
+ uptodate[k] = self.site.GLOBAL_CONTEXT[k](kw['default_lang'])
+
+ uptodate2 = uptodate.copy()
+ uptodate2['f'] = files
+ uptodate2['d'] = dirs
+
# Render all files
out_name = os.path.join(
kw['output_folder'],
@@ -105,8 +141,7 @@ class Listings(Task):
'actions': [(render_listing, [None, out_name, dirs, files])],
# This is necessary to reflect changes in blog title,
# sidebar links, etc.
- 'uptodate': [utils.config_changed(
- self.site.GLOBAL_CONTEXT)],
+ 'uptodate': [utils.config_changed(uptodate2)],
'clean': True,
}
for f in files:
@@ -126,11 +161,25 @@ class Listings(Task):
'actions': [(render_listing, [in_name, out_name])],
# This is necessary to reflect changes in blog title,
# sidebar links, etc.
- 'uptodate': [utils.config_changed(
- self.site.GLOBAL_CONTEXT)],
+ 'uptodate': [utils.config_changed(uptodate)],
'clean': True,
}
+ if self.site.config['COPY_SOURCES']:
+ out_name = os.path.join(
+ kw['output_folder'],
+ root,
+ f)
+ yield {
+ 'basename': self.name,
+ 'name': out_name,
+ 'file_dep': [in_name],
+ 'targets': [out_name],
+ 'actions': [(utils.copy_file, [in_name, out_name])],
+ 'clean': True,
+ }
def listing_path(self, name, lang):
- return [_f for _f in [self.site.config['LISTINGS_FOLDER'], name +
- '.html'] if _f]
+ if not name.endswith('.html'):
+ name += '.html'
+ path_parts = [self.site.config['LISTINGS_FOLDER']] + list(os.path.split(name))
+ return [_f for _f in path_parts if _f]
diff --git a/nikola/plugins/task/localsearch.plugin b/nikola/plugins/task/localsearch.plugin
deleted file mode 100644
index 86accb6..0000000
--- a/nikola/plugins/task/localsearch.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = local_search
-Module = localsearch
-
-[Documentation]
-Author = Roberto Alsina
-Version = 0.1
-Website = http://getnikola.com
-Description = Create data files for local search via Tipue
-
diff --git a/nikola/plugins/task/localsearch/__init__.py b/nikola/plugins/task/localsearch/__init__.py
deleted file mode 100644
index c501d80..0000000
--- a/nikola/plugins/task/localsearch/__init__.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-from __future__ import unicode_literals
-import codecs
-import json
-import os
-
-from doit.tools import result_dep
-
-from nikola.plugin_categories import LateTask
-from nikola.utils import config_changed, copy_tree, makedirs
-
-# This is what we need to produce:
-#var tipuesearch = {"pages": [
- #{"title": "Tipue Search, a jQuery site search engine", "text": "Tipue
- #Search is a site search engine jQuery plugin. It's free for both commercial and
- #non-commercial use and released under the MIT License. Tipue Search includes
- #features such as word stemming and word replacement.", "tags": "JavaScript",
- #"loc": "http://www.tipue.com/search"},
- #{"title": "Tipue Search demo", "text": "Tipue Search demo. Tipue Search is
- #a site search engine jQuery plugin.", "tags": "JavaScript", "loc":
- #"http://www.tipue.com/search/demo"},
- #{"title": "About Tipue", "text": "Tipue is a small web development/design
- #studio based in North London. We've been around for over a decade.", "tags": "",
- #"loc": "http://www.tipue.com/about"}
-#]};
-
-
-class Tipue(LateTask):
- """Render the blog posts as JSON data."""
-
- name = "local_search"
-
- def gen_tasks(self):
- self.site.scan_posts()
-
- kw = {
- "translations": self.site.config['TRANSLATIONS'],
- "output_folder": self.site.config['OUTPUT_FOLDER'],
- }
-
- posts = self.site.timeline[:]
- dst_path = os.path.join(kw["output_folder"], "assets", "js",
- "tipuesearch_content.json")
-
- def save_data():
- pages = []
- for lang in kw["translations"]:
- for post in posts:
- # Don't index drafts (Issue #387)
- if post.is_draft or post.is_retired or post.publish_later:
- continue
- text = post.text(lang, strip_html=True)
- text = text.replace('^', '')
-
- data = {}
- data["title"] = post.title(lang)
- data["text"] = text
- data["tags"] = ",".join(post.tags)
- data["loc"] = post.permalink(lang)
- pages.append(data)
- output = json.dumps({"pages": pages}, indent=2)
- makedirs(os.path.dirname(dst_path))
- with codecs.open(dst_path, "wb+", "utf8") as fd:
- fd.write(output)
-
- yield {
- "basename": str(self.name),
- "name": dst_path,
- "targets": [dst_path],
- "actions": [(save_data, [])],
- 'uptodate': [config_changed(kw), result_dep('sitemap')]
- }
- # Note: The task should run everytime a new file is added or a
- # file is changed. We cheat, and depend on the sitemap task,
- # to run everytime a new file is added.
-
- # Copy all the assets to the right places
- asset_folder = os.path.join(os.path.dirname(__file__), "files")
- for task in copy_tree(asset_folder, kw["output_folder"]):
- task["basename"] = str(self.name)
- yield task
diff --git a/nikola/plugins/task/localsearch/files/assets/css/img/loader.gif b/nikola/plugins/task/localsearch/files/assets/css/img/loader.gif
deleted file mode 100644
index 9c97738..0000000
--- a/nikola/plugins/task/localsearch/files/assets/css/img/loader.gif
+++ /dev/null
Binary files differ
diff --git a/nikola/plugins/task/localsearch/files/assets/css/img/search.png b/nikola/plugins/task/localsearch/files/assets/css/img/search.png
deleted file mode 100644
index 9ab0f2c..0000000
--- a/nikola/plugins/task/localsearch/files/assets/css/img/search.png
+++ /dev/null
Binary files differ
diff --git a/nikola/plugins/task/localsearch/files/assets/css/tipuesearch.css b/nikola/plugins/task/localsearch/files/assets/css/tipuesearch.css
deleted file mode 100644
index 2230193..0000000
--- a/nikola/plugins/task/localsearch/files/assets/css/tipuesearch.css
+++ /dev/null
@@ -1,159 +0,0 @@
-
-/*
-Tipue Search 3.0.1
-Copyright (c) 2013 Tipue
-Tipue Search is released under the MIT License
-http://www.tipue.com/search
-*/
-
-
-#tipue_search_input
-{
- font: 12px/1.7 'open sans', sans-serif;
- color: #333;
- padding: 7px;
- width: 150px;
- border: 1px solid #e2e2e2;
- border-radius: 0;
- -moz-appearance: none;
- -webkit-appearance: none;
- box-shadow: none;
- outline: 0;
- margin: 0;
-}
-#tipue_search_input:focus
-{
- border: 1px solid #ccc;
-}
-#tipue_search_button
-{
- width: 70px;
- height: 36px;
- border: 0;
- border-radius: 1px;
- background: #5193fb url('img/search.png') no-repeat center;
- outline: none;
-}
-#tipue_search_button:hover
-{
- background-color: #4589fb;
-}
-
-#tipue_search_content
-{
- clear: left;
- max-width: 650px;
- padding: 25px 0 13px 0;
- margin: 0;
-}
-#tipue_search_loading
-{
- padding-top: 60px;
- background: #fff url('img/loader.gif') no-repeat left;
-}
-
-#tipue_search_warning_head
-{
- font: 300 16px/1.6 'open sans', sans-serif;
- color: #333;
-}
-#tipue_search_warning
-{
- font: 12px/1.6 'open sans', sans-serif;
- color: #333;
- margin: 7px 0;
-}
-#tipue_search_warning a
-{
- color: #3f72d8;
- text-decoration: none;
-}
-#tipue_search_warning a:hover
-{
- padding-bottom: 1px;
- border-bottom: 1px solid #ccc;
-}
-#tipue_search_results_count
-{
- font: 13px/1.6 'open sans', sans-serif;
- color: #333;
-}
-.tipue_search_content_title
-{
- font: 300 23px/1.6 'open sans', sans-serif;
- margin-top: 31px;
-}
-.tipue_search_content_title a
-{
- color: #3f72d8;
- text-decoration: none;
-}
-.tipue_search_content_title a:hover
-{
- padding-bottom: 1px;
- border-bottom: 1px solid #ccc;
-}
-.tipue_search_content_text
-{
- font: 12px/1.7 'open sans', sans-serif;
- color: #333;
- padding: 13px 0;
-}
-.tipue_search_content_loc
-{
- font: 300 13px/1.7 'open sans', sans-serif;
- overflow: auto;
-}
-.tipue_search_content_loc a
-{
- color: #555;
- text-decoration: none;
-}
-.tipue_search_content_loc a:hover
-{
- padding-bottom: 1px;
- border-bottom: 1px solid #ccc;
-}
-#tipue_search_foot
-{
- margin: 51px 0 21px 0;
-}
-#tipue_search_foot_boxes
-{
- padding: 0;
- margin: 0;
- font: 12px/1 'open sans', sans-serif;
-}
-#tipue_search_foot_boxes li
-{
- list-style: none;
- margin: 0;
- padding: 0;
- display: inline;
-}
-#tipue_search_foot_boxes li a
-{
- padding: 7px 13px 8px 13px;
- background-color: #f1f1f1;
- border: 1px solid #dcdcdc;
- border-radius: 1px;
- color: #333;
- margin-right: 7px;
- text-decoration: none;
- text-align: center;
-}
-#tipue_search_foot_boxes li.current
-{
- padding: 7px 13px 8px 13px;
- background: #fff;
- border: 1px solid #dcdcdc;
- border-radius: 1px;
- color: #333;
- margin-right: 7px;
- text-align: center;
-}
-#tipue_search_foot_boxes li a:hover
-{
- border: 1px solid #ccc;
- background-color: #f3f3f3;
-}
diff --git a/nikola/plugins/task/localsearch/files/assets/js/tipuesearch.js b/nikola/plugins/task/localsearch/files/assets/js/tipuesearch.js
deleted file mode 100644
index a9982cd..0000000
--- a/nikola/plugins/task/localsearch/files/assets/js/tipuesearch.js
+++ /dev/null
@@ -1,384 +0,0 @@
-
-/*
-Tipue Search 3.0.1
-Copyright (c) 2013 Tipue
-Tipue Search is released under the MIT License
-http://www.tipue.com/search
-*/
-
-
-(function($) {
-
- $.fn.tipuesearch = function(options) {
-
- var set = $.extend( {
-
- 'show' : 7,
- 'newWindow' : false,
- 'showURL' : true,
- 'minimumLength' : 3,
- 'descriptiveWords' : 25,
- 'highlightTerms' : true,
- 'highlightEveryTerm' : false,
- 'mode' : 'static',
- 'liveDescription' : '*',
- 'liveContent' : '*',
- 'contentLocation' : 'tipuesearch/tipuesearch_content.json'
-
- }, options);
-
- return this.each(function() {
-
- var tipuesearch_in = {
- pages: []
- };
- $.ajaxSetup({
- async: false
- });
-
- if (set.mode == 'live')
- {
- for (var i = 0; i < tipuesearch_pages.length; i++)
- {
- $.get(tipuesearch_pages[i], '',
- function (html)
- {
- var cont = $(set.liveContent, html).text();
- cont = cont.replace(/\s+/g, ' ');
- var desc = $(set.liveDescription, html).text();
- desc = desc.replace(/\s+/g, ' ');
-
- var t_1 = html.toLowerCase().indexOf('<title>');
- var t_2 = html.toLowerCase().indexOf('</title>', t_1 + 7);
- if (t_1 != -1 && t_2 != -1)
- {
- var tit = html.slice(t_1 + 7, t_2);
- }
- else
- {
- var tit = 'No title';
- }
-
- tipuesearch_in.pages.push({
- "title": tit,
- "text": desc,
- "tags": cont,
- "loc": tipuesearch_pages[i]
- });
- }
- );
- }
- }
-
- if (set.mode == 'json')
- {
- $.getJSON(set.contentLocation,
- function(json)
- {
- tipuesearch_in = $.extend({}, json);
- }
- );
- }
-
- if (set.mode == 'static')
- {
- tipuesearch_in = $.extend({}, tipuesearch);
- }
-
- var tipue_search_w = '';
- if (set.newWindow)
- {
- tipue_search_w = ' target="_blank"';
- }
-
- function getURLP(name)
- {
- return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20')) || null;
- }
- if (getURLP('q'))
- {
- $('#tipue_search_input').val(getURLP('q'));
- getTipueSearch(0, true);
- }
-
- $('#tipue_search_button').click(function()
- {
- getTipueSearch(0, true);
- });
- $(this).keyup(function(event)
- {
- if(event.keyCode == '13')
- {
- getTipueSearch(0, true);
- }
- });
-
- function getTipueSearch(start, replace)
- {
- $('#tipue_search_content').hide();
- var out = '';
- var results = '';
- var show_replace = false;
- var show_stop = false;
-
- var d = $('#tipue_search_input').val().toLowerCase();
- d = $.trim(d);
- var d_w = d.split(' ');
- d = '';
- for (var i = 0; i < d_w.length; i++)
- {
- var a_w = true;
- for (var f = 0; f < tipuesearch_stop_words.length; f++)
- {
- if (d_w[i] == tipuesearch_stop_words[f])
- {
- a_w = false;
- show_stop = true;
- }
- }
- if (a_w)
- {
- d = d + ' ' + d_w[i];
- }
- }
- d = $.trim(d);
- d_w = d.split(' ');
-
- if (d.length >= set.minimumLength)
- {
- if (replace)
- {
- var d_r = d;
- for (var i = 0; i < d_w.length; i++)
- {
- for (var f = 0; f < tipuesearch_replace.words.length; f++)
- {
- if (d_w[i] == tipuesearch_replace.words[f].word)
- {
- d = d.replace(d_w[i], tipuesearch_replace.words[f].replace_with);
- show_replace = true;
- }
- }
- }
- d_w = d.split(' ');
- }
-
- var d_t = d;
- for (var i = 0; i < d_w.length; i++)
- {
- for (var f = 0; f < tipuesearch_stem.words.length; f++)
- {
- if (d_w[i] == tipuesearch_stem.words[f].word)
- {
- d_t = d_t + ' ' + tipuesearch_stem.words[f].stem;
- }
- }
- }
- d_w = d_t.split(' ');
-
- var c = 0;
- found = new Array();
- for (var i = 0; i < tipuesearch_in.pages.length; i++)
- {
- var score = 1000000000;
- var s_t = tipuesearch_in.pages[i].text;
- for (var f = 0; f < d_w.length; f++)
- {
- var pat = new RegExp(d_w[f], 'i');
- if (tipuesearch_in.pages[i].title.search(pat) != -1)
- {
- score -= (200000 - i);
- }
- if (tipuesearch_in.pages[i].text.search(pat) != -1)
- {
- score -= (150000 - i);
- }
-
- if (set.highlightTerms)
- {
- if (set.highlightEveryTerm)
- {
- var patr = new RegExp('(' + d_w[f] + ')', 'gi');
- }
- else
- {
- var patr = new RegExp('(' + d_w[f] + ')', 'i');
- }
- s_t = s_t.replace(patr, "<b>$1</b>");
- }
- if (tipuesearch_in.pages[i].tags.search(pat) != -1)
- {
- score -= (100000 - i);
- }
-
- }
- if (score < 1000000000)
- {
- found[c++] = score + '^' + tipuesearch_in.pages[i].title + '^' + s_t + '^' + tipuesearch_in.pages[i].loc;
- }
- }
-
- if (c != 0)
- {
- if (show_replace == 1)
- {
- out += '<div id="tipue_search_warning_head">Showing results for ' + d + '</div>';
- out += '<div id="tipue_search_warning">Search for <a href="javascript:void(0)" id="tipue_search_replaced">' + d_r + '</a></div>';
- }
- if (c == 1)
- {
- out += '<div id="tipue_search_results_count">1 result</div>';
- }
- else
- {
- c_c = c.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
- out += '<div id="tipue_search_results_count">' + c_c + ' results</div>';
- }
-
- found.sort();
- var l_o = 0;
- for (var i = 0; i < found.length; i++)
- {
- var fo = found[i].split('^');
- if (l_o >= start && l_o < set.show + start)
- {
- out += '<div class="tipue_search_content_title"><a href="' + fo[3] + '"' + tipue_search_w + '>' + fo[1] + '</a></div>';
-
- var t = fo[2];
- var t_d = '';
- var t_w = t.split(' ');
- if (t_w.length < set.descriptiveWords)
- {
- t_d = t;
- }
- else
- {
- for (var f = 0; f < set.descriptiveWords; f++)
- {
- t_d += t_w[f] + ' ';
- }
- }
- t_d = $.trim(t_d);
- if (t_d.charAt(t_d.length - 1) != '.')
- {
- t_d += ' ...';
- }
- out += '<div class="tipue_search_content_text">' + t_d + '</div>';
-
- if (set.showURL)
- {
- t_url = fo[3];
- if (t_url.length > 45)
- {
- t_url = fo[3].substr(0, 45) + ' ...';
- }
- out += '<div class="tipue_search_content_loc"><a href="' + fo[3] + '"' + tipue_search_w + '>' + t_url + '</a></div>';
- }
- }
- l_o++;
- }
-
- if (c > set.show)
- {
- var pages = Math.ceil(c / set.show);
- var page = (start / set.show);
- out += '<div id="tipue_search_foot"><ul id="tipue_search_foot_boxes">';
-
- if (start > 0)
- {
- out += '<li><a href="javascript:void(0)" class="tipue_search_foot_box" id="' + (start - set.show) + '_' + replace + '">Prev</a></li>';
- }
-
- if (page <= 2)
- {
- var p_b = pages;
- if (pages > 3)
- {
- p_b = 3;
- }
- for (var f = 0; f < p_b; f++)
- {
- if (f == page)
- {
- out += '<li class="current">' + (f + 1) + '</li>';
- }
- else
- {
- out += '<li><a href="javascript:void(0)" class="tipue_search_foot_box" id="' + (f * set.show) + '_' + replace + '">' + (f + 1) + '</a></li>';
- }
- }
- }
- else
- {
- var p_b = page + 3;
- if (p_b > pages)
- {
- p_b = pages;
- }
- for (var f = page; f < p_b; f++)
- {
- if (f == page)
- {
- out += '<li class="current">' + (f + 1) + '</li>';
- }
- else
- {
- out += '<li><a href="javascript:void(0)" class="tipue_search_foot_box" id="' + (f * set.show) + '_' + replace + '">' + (f + 1) + '</a></li>';
- }
- }
- }
-
- if (page + 1 != pages)
- {
- out += '<li><a href="javascript:void(0)" class="tipue_search_foot_box" id="' + (start + set.show) + '_' + replace + '">Next</a></li>';
- }
-
- out += '</ul></div>';
- }
- }
- else
- {
- out += '<div id="tipue_search_warning_head">Nothing found</div>';
- }
- }
- else
- {
- if (show_stop)
- {
- out += '<div id="tipue_search_warning_head">Nothing found</div><div id="tipue_search_warning">Common words are largely ignored</div>';
- }
- else
- {
- out += '<div id="tipue_search_warning_head">Search too short</div>';
- if (set.minimumLength == 1)
- {
- out += '<div id="tipue_search_warning">Should be one character or more</div>';
- }
- else
- {
- out += '<div id="tipue_search_warning">Should be ' + set.minimumLength + ' characters or more</div>';
- }
- }
- }
-
- $('#tipue_search_content').html(out);
- $('#tipue_search_content').slideDown(200);
-
- $('#tipue_search_replaced').click(function()
- {
- getTipueSearch(0, false);
- });
-
- $('.tipue_search_foot_box').click(function()
- {
- var id_v = $(this).attr('id');
- var id_a = id_v.split('_');
-
- getTipueSearch(parseInt(id_a[0]), id_a[1]);
- });
- }
-
- });
- };
-
-})(jQuery);
diff --git a/nikola/plugins/task/localsearch/files/assets/js/tipuesearch_set.js b/nikola/plugins/task/localsearch/files/assets/js/tipuesearch_set.js
deleted file mode 100644
index 8493ec1..0000000
--- a/nikola/plugins/task/localsearch/files/assets/js/tipuesearch_set.js
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/*
-Tipue Search 3.0.1
-Copyright (c) 2013 Tipue
-Tipue Search is released under the MIT License
-http://www.tipue.com/search
-*/
-
-
-var tipuesearch_stop_words = ["and", "be", "by", "do", "for", "he", "how", "if", "is", "it", "my", "not", "of", "or", "the", "to", "up", "what", "when"];
-
-var tipuesearch_replace = {"words": [
- {"word": "tipua", replace_with: "tipue"},
- {"word": "javscript", replace_with: "javascript"}
-]};
-
-var tipuesearch_stem = {"words": [
- {"word": "e-mail", stem: "email"},
- {"word": "javascript", stem: "script"},
- {"word": "javascript", stem: "js"}
-]};
diff --git a/nikola/plugins/task/localsearch/files/tipue_search.html b/nikola/plugins/task/localsearch/files/tipue_search.html
deleted file mode 100644
index 789fbe5..0000000
--- a/nikola/plugins/task/localsearch/files/tipue_search.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-
-<html>
-<head>
-<title>Tipue Search</title>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
-
-<link rel="stylesheet" type="text/css" href="assets/css/tipuesearch.css">
-<script type="text/javascript" src="assets/js/tipuesearch_set.js"></script>
-<script type="text/javascript" src="assets/js/tipuesearch.js"></script>
-
-</head>
-<body>
-
-<div style="float: left;"><input type="text" id="tipue_search_input"></div>
-<div style="float: left; margin-left: 13px;"><input type="button" id="tipue_search_button"></div>
-<div id="tipue_search_content"><div id="tipue_search_loading"></div></div>
-</div>
-
-<script type="text/javascript">
-$(document).ready(function() {
- $('#tipue_search_input').tipuesearch({
- 'mode': 'json',
- 'contentLocation': 'assets/js/tipuesearch_content.json'
- });
-});
-</script>
-</body>
-</html>
diff --git a/nikola/plugins/task/mustache.plugin b/nikola/plugins/task/mustache.plugin
deleted file mode 100644
index d6b487a..0000000
--- a/nikola/plugins/task/mustache.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = render_mustache
-Module = mustache
-
-[Documentation]
-Author = Roberto Alsina
-Version = 0.1
-Website = http://getnikola.com
-Description = Generates the blog's index pages in json.
-
diff --git a/nikola/plugins/task/mustache/__init__.py b/nikola/plugins/task/mustache/__init__.py
deleted file mode 100644
index 5be98f0..0000000
--- a/nikola/plugins/task/mustache/__init__.py
+++ /dev/null
@@ -1,184 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-from __future__ import unicode_literals
-
-import codecs
-import json
-import os
-
-from nikola.plugin_categories import Task
-from nikola.utils import (
- config_changed, copy_file, LocaleBorg, makedirs, unicode_str,
-)
-
-
-class Mustache(Task):
- """Render the blog posts as JSON data."""
-
- name = "render_mustache"
-
- def gen_tasks(self):
- self.site.scan_posts()
-
- kw = {
- "translations": self.site.config['TRANSLATIONS'],
- "index_display_post_count":
- self.site.config['INDEX_DISPLAY_POST_COUNT'],
- "messages": self.site.MESSAGES,
- "index_teasers": self.site.config['INDEX_TEASERS'],
- "output_folder": self.site.config['OUTPUT_FOLDER'],
- "filters": self.site.config['FILTERS'],
- "blog_title": self.site.config['BLOG_TITLE'],
- "content_footer": self.site.config['CONTENT_FOOTER'],
- }
-
- # TODO: timeline is global, get rid of it
- posts = [x for x in self.site.timeline if x.use_in_feeds]
- if not posts:
- yield {
- 'basename': 'render_mustache',
- 'actions': [],
- }
- return
-
- def write_file(path, post, lang):
-
- # Prev/Next links
- prev_link = False
- if post.prev_post:
- prev_link = post.prev_post.permalink(lang).replace(".html",
- ".json")
- next_link = False
- if post.next_post:
- next_link = post.next_post.permalink(lang).replace(".html",
- ".json")
- data = {}
-
- # Configuration
- for k, v in self.site.config.items():
- if isinstance(v, (str, unicode_str)): # NOQA
- data[k] = v
-
- # Tag data
- tags = []
- for tag in post.tags:
- tags.append({'name': tag, 'link': self.site.link("tag", tag,
- lang)})
- data.update({
- "tags": tags,
- "tags?": True if tags else False,
- })
-
- # Template strings
- for k, v in kw["messages"][lang].items():
- data["message_" + k] = v
-
- # Post data
- data.update({
- "title": post.title(lang),
- "text": post.text(lang),
- "prev": prev_link,
- "next": next_link,
- "date":
- post.date.strftime(self.site.GLOBAL_CONTEXT['date_format']),
- })
-
- # Comments
- context = dict(post=post, lang=LocaleBorg().current_lang)
- context.update(self.site.GLOBAL_CONTEXT)
- data["comment_html"] = self.site.template_system.render_template(
- 'mustache-comment-form.tmpl', None, context).strip()
-
- # Post translations
- translations = []
- for langname in kw["translations"]:
- if langname == lang:
- continue
- translations.append({'name':
- kw["messages"][langname]["Read in English"],
- 'link': "javascript:load_data('%s');"
- % post.permalink(langname).replace(
- ".html", ".json")})
- data["translations"] = translations
-
- makedirs(os.path.dirname(path))
- with codecs.open(path, 'wb+', 'utf8') as fd:
- fd.write(json.dumps(data))
-
- for lang in kw["translations"]:
- for i, post in enumerate(posts):
- out_path = post.destination_path(lang, ".json")
- out_file = os.path.join(kw['output_folder'], out_path)
- task = {
- 'basename': 'render_mustache',
- 'name': out_file,
- 'file_dep': post.fragment_deps(lang),
- 'targets': [out_file],
- 'actions': [(write_file, (out_file, post, lang))],
- 'task_dep': ['render_posts'],
- 'uptodate': [config_changed({
- 1: post.text(lang),
- 2: post.prev_post,
- 3: post.next_post,
- 4: post.title(lang),
- })]
- }
- yield task
-
- if posts:
- first_post_data = posts[0].permalink(
- self.site.config["DEFAULT_LANG"]).replace(".html", ".json")
-
- # Copy mustache template
- src = os.path.join(os.path.dirname(__file__), 'mustache-template.html')
- dst = os.path.join(kw['output_folder'], 'mustache-template.html')
- yield {
- 'basename': 'render_mustache',
- 'name': dst,
- 'targets': [dst],
- 'file_dep': [src],
- 'actions': [(copy_file, (src, dst))],
- }
-
- # Copy mustache.html with the right starting file in it
- src = os.path.join(os.path.dirname(__file__), 'mustache.html')
- dst = os.path.join(kw['output_folder'], 'mustache.html')
-
- def copy_mustache():
- with codecs.open(src, 'rb', 'utf8') as in_file:
- with codecs.open(dst, 'wb+', 'utf8') as out_file:
- data = in_file.read().replace('{{first_post_data}}',
- first_post_data)
- out_file.write(data)
- yield {
- 'basename': 'render_mustache',
- 'name': dst,
- 'targets': [dst],
- 'file_dep': [src],
- 'uptodate': [config_changed({1: first_post_data})],
- 'actions': [(copy_mustache, [])],
- }
diff --git a/nikola/plugins/task/mustache/mustache-template.html b/nikola/plugins/task/mustache/mustache-template.html
deleted file mode 100644
index e9a0213..0000000
--- a/nikola/plugins/task/mustache/mustache-template.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<script id="view" type="text/html">
-<div class="container" id="container">
- <div class="postbox">
- <h1>{{BLOG_TITLE}}</h1>
- <hr>
- <h2>{{title}}</h2>
- Posted on: {{date}}</br>
- {{#tags?}} More posts about:
- {{#tags}}<a class="tag" href={{link}}><span class="badge badge-info">{{name}}</span></a>{{/tags}}
- </br>
- {{/tags?}}
- {{#translations}}<a href={{link}}>{{name}}</a>{{/translations}}&nbsp;</br>
- <hr>
- {{{text}}}
- <ul class="pager">
- {{#prev}}
- <li class="previous"><a href="javascript:load_data('{{prev}}')">{{message_Previous post}}</a></li>
- {{/prev}}
- {{#next}}
- <li class="next"><a href="javascript:load_data('{{next}}')">{{message_Next post}}</a></li>
- {{/next}}
- </ul>
- {{{comment_html}}}
- </div>
- <div class="footerbox">
- {{{CONTENT_FOOTER}}}
- </div>
-</div>
-</script>
diff --git a/nikola/plugins/task/mustache/mustache.html b/nikola/plugins/task/mustache/mustache.html
deleted file mode 100644
index 7ff6312..0000000
--- a/nikola/plugins/task/mustache/mustache.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<head>
- <link href="/assets/css/bootstrap.css" rel="stylesheet" type="text/css">
- <link href="/assets/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
- <link href="/assets/css/rst.css" rel="stylesheet" type="text/css">
- <link href="/assets/css/code.css" rel="stylesheet" type="text/css">
- <link href="/assets/css/colorbox.css" rel="stylesheet" type="text/css"/>
- <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"/>
- <link href="/assets/css/custom.css" rel="stylesheet" type="text/css">
- <script src="/assets/js/jquery-1.10.2.min.js" type="text/javascript"></script>
- <script src="//cdn.jsdelivr.net/jquery.mustache/0.2.7/jquery.mustache.js"></script>
- <script src="//cdn.jsdelivr.net/mustache.js/0.7.2/mustache.js"></script>
- <script src="/assets/js/jquery.colorbox-min.js" type="text/javascript"></script>
- <script type="text/javascript">
-function load_data(dataurl) {
- jQuery.getJSON(dataurl, function(data) {
- $('body').mustache('view', data, { method: 'html' });
- window.location.hash = '#' + dataurl;
- })
-};
-$(document).ready(function() {
-$.Mustache.load('/mustache-template.html')
- .done(function () {
- if (window.location.hash != '') {
- load_data(window.location.hash.slice(1));
- }
- else {
- load_data('{{first_post_data}}');
- };
- })
-});
-</script>
-</head>
-<body style="padding-top: 0;">
-</body>
diff --git a/nikola/plugins/task/pages.py b/nikola/plugins/task/pages.py
index f4c0469..aefc5a1 100644
--- a/nikola/plugins/task/pages.py
+++ b/nikola/plugins/task/pages.py
@@ -40,13 +40,14 @@ class RenderPages(Task):
"post_pages": self.site.config["post_pages"],
"translations": self.site.config["TRANSLATIONS"],
"filters": self.site.config["FILTERS"],
- "hide_untranslated_posts": self.site.config['HIDE_UNTRANSLATED_POSTS'],
+ "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
+ "demote_headers": self.site.config['DEMOTE_HEADERS'],
}
self.site.scan_posts()
yield self.group_task()
for lang in kw["translations"]:
for post in self.site.timeline:
- if kw["hide_untranslated_posts"] and not post.is_translation_available(lang):
+ if not kw["show_untranslated_posts"] and not post.is_translation_available(lang):
continue
for task in self.site.generic_page_renderer(lang, post,
kw["filters"]):
diff --git a/nikola/plugins/task/posts.py b/nikola/plugins/task/posts.py
index a502b81..8e03122 100644
--- a/nikola/plugins/task/posts.py
+++ b/nikola/plugins/task/posts.py
@@ -25,12 +25,20 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from copy import copy
-import nikola.post
from nikola.plugin_categories import Task
from nikola import utils
+def rest_deps(post, task):
+ """Add extra_deps from ReST into task.
+
+ The .dep file is created by ReST so not available before the task starts
+ to execute.
+ """
+ task.file_dep.update(post.extra_deps())
+
+
class RenderPosts(Task):
"""Build HTML fragments from metadata and text."""
@@ -43,10 +51,10 @@ class RenderPosts(Task):
"translations": self.site.config["TRANSLATIONS"],
"timeline": self.site.timeline,
"default_lang": self.site.config["DEFAULT_LANG"],
- "hide_untranslated_posts": self.site.config['HIDE_UNTRANSLATED_POSTS'],
+ "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
+ "demote_headers": self.site.config['DEMOTE_HEADERS'],
}
- nikola.post.READ_MORE_LINK = self.site.config['READ_MORE_LINK']
yield self.group_task()
for lang in kw["translations"]:
@@ -59,7 +67,9 @@ class RenderPosts(Task):
'name': dest,
'file_dep': post.fragment_deps(lang),
'targets': [dest],
- 'actions': [(post.compile, (lang, ))],
+ 'actions': [(post.compile, (lang, )),
+ (rest_deps, (post,)),
+ ],
'clean': True,
'uptodate': [utils.config_changed(deps_dict)],
}
diff --git a/nikola/plugins/task/redirect.py b/nikola/plugins/task/redirect.py
index 6fafd13..eccc0ab 100644
--- a/nikola/plugins/task/redirect.py
+++ b/nikola/plugins/task/redirect.py
@@ -63,4 +63,4 @@ def create_redirect(src, dst):
with codecs.open(src, "wb+", "utf8") as fd:
fd.write('<!DOCTYPE html><head><title>Redirecting...</title>'
'<meta http-equiv="refresh" content="0; '
- 'url={0}"></head>'.format(dst))
+ 'url={0}"></head><body><p>Page moved <a href="{0}">here</a></p></body>'.format(dst))
diff --git a/nikola/plugins/task/robots.plugin b/nikola/plugins/task/robots.plugin
new file mode 100644
index 0000000..60b50fb
--- /dev/null
+++ b/nikola/plugins/task/robots.plugin
@@ -0,0 +1,10 @@
+[Core]
+Name = robots
+Module = robots
+
+[Documentation]
+Author = Daniel Aleksandersen
+Version = 0.1
+Website = http://getnikola.com
+Description = Generate /robots.txt exclusion file and promote sitemap.
+
diff --git a/nikola/plugins/task/robots.py b/nikola/plugins/task/robots.py
new file mode 100644
index 0000000..9944c0d
--- /dev/null
+++ b/nikola/plugins/task/robots.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2012-2014 Roberto Alsina and others.
+
+# Permission is hereby granted, free of charge, to any
+# person obtaining a copy of this software and associated
+# documentation files (the "Software"), to deal in the
+# Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the
+# Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice
+# shall be included in all copies or substantial portions of
+# the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+from __future__ import print_function, absolute_import, unicode_literals
+import codecs
+import os
+try:
+ from urlparse import urljoin, urlparse
+except ImportError:
+ from urllib.parse import urljoin, urlparse # NOQA
+
+from nikola.plugin_categories import LateTask
+from nikola import utils
+
+
+class RobotsFile(LateTask):
+ """Generate a robots.txt."""
+
+ name = "robots_file"
+
+ def gen_tasks(self):
+ """Generate a robots.txt."""
+ kw = {
+ "base_url": self.site.config["BASE_URL"],
+ "site_url": self.site.config["SITE_URL"],
+ "output_folder": self.site.config["OUTPUT_FOLDER"],
+ "files_folders": self.site.config['FILES_FOLDERS'],
+ "robots_exclusions": self.site.config["ROBOTS_EXCLUSIONS"]
+ }
+
+ if kw["site_url"] != urljoin(kw["site_url"], "/"):
+ utils.LOGGER.warn('robots.txt not ending up in server root, will be useless')
+
+ sitemapindex_url = urljoin(kw["base_url"], "sitemapindex.xml")
+ robots_path = os.path.join(kw['output_folder'], "robots.txt")
+
+ def write_robots():
+ with codecs.open(robots_path, 'wb+', 'utf8') as outf:
+ outf.write("Sitemap: {0}\n\n".format(sitemapindex_url))
+ if kw["robots_exclusions"]:
+ outf.write("User-Agent: *\n")
+ for loc in kw["robots_exclusions"]:
+ outf.write("Disallow: {0}\n".format(loc))
+
+ yield self.group_task()
+
+ if not utils.get_asset_path("robots.txt", [], files_folders=kw["files_folders"]):
+ yield {
+ "basename": self.name,
+ "name": robots_path,
+ "targets": [robots_path],
+ "actions": [(write_robots)],
+ "uptodate": [utils.config_changed(kw)],
+ "clean": True,
+ "task_dep": ["sitemap"]
+ }
+ elif kw["robots_exclusions"]:
+ utils.LOGGER.warn('Did not generate robots.txt as one already exists in FILES_FOLDERS. ROBOTS_EXCLUSIONS will not have any affect on the copied fie.')
+ else:
+ utils.LOGGER.debug('Did not generate robots.txt as one already exists in FILES_FOLDERS.')
diff --git a/nikola/plugins/task/rss.py b/nikola/plugins/task/rss.py
index 9e4204c..b16ed48 100644
--- a/nikola/plugins/task/rss.py
+++ b/nikola/plugins/task/rss.py
@@ -54,8 +54,11 @@ class GenerateRSS(Task):
"blog_description": self.site.config["BLOG_DESCRIPTION"],
"output_folder": self.site.config["OUTPUT_FOLDER"],
"rss_teasers": self.site.config["RSS_TEASERS"],
- "hide_untranslated_posts": self.site.config['HIDE_UNTRANSLATED_POSTS'],
+ "rss_plain": self.site.config["RSS_PLAIN"],
+ "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
"feed_length": self.site.config['FEED_LENGTH'],
+ "tzinfo": self.site.tzinfo,
+ "rss_read_more_link": self.site.config["RSS_READ_MORE_LINK"],
}
self.site.scan_posts()
# Check for any changes in the state of use_in_feeds for any post.
@@ -68,24 +71,25 @@ class GenerateRSS(Task):
output_name = os.path.join(kw['output_folder'],
self.site.path("rss", None, lang))
deps = []
- if kw["hide_untranslated_posts"]:
- posts = [x for x in self.site.timeline if x.use_in_feeds
- and x.is_translation_available(lang)][:10]
+ if kw["show_untranslated_posts"]:
+ posts = self.site.posts[:10]
else:
- posts = [x for x in self.site.timeline if x.use_in_feeds][:10]
+ posts = [x for x in self.site.posts if x.is_translation_available(lang)][:10]
for post in posts:
deps += post.deps(lang)
feed_url = urljoin(self.site.config['BASE_URL'], self.site.link("rss", None, lang).lstrip('/'))
+
yield {
'basename': 'generate_rss',
'name': os.path.normpath(output_name),
'file_dep': deps,
'targets': [output_name],
'actions': [(utils.generic_rss_renderer,
- (lang, kw["blog_title"], kw["site_url"],
- kw["blog_description"], posts, output_name,
- kw["rss_teasers"], kw['feed_length'], feed_url))],
+ (lang, kw["blog_title"](lang), kw["site_url"],
+ kw["blog_description"](lang), posts, output_name,
+ kw["rss_teasers"], kw["rss_plain"], kw['feed_length'], feed_url))],
+
'task_dep': ['render_posts'],
'clean': True,
'uptodate': [utils.config_changed(kw)],
diff --git a/nikola/plugins/task/sitemap/__init__.py b/nikola/plugins/task/sitemap/__init__.py
index 147bd50..beac6cb 100644
--- a/nikola/plugins/task/sitemap/__init__.py
+++ b/nikola/plugins/task/sitemap/__init__.py
@@ -30,14 +30,16 @@ import datetime
import os
try:
from urlparse import urljoin, urlparse
+ import robotparser as robotparser
except ImportError:
from urllib.parse import urljoin, urlparse # NOQA
+ import urllib.robotparser as robotparser # NOQA
from nikola.plugin_categories import LateTask
from nikola.utils import config_changed
-header = """<?xml version="1.0" encoding="UTF-8"?>
+urlset_header = """<?xml version="1.0" encoding="UTF-8"?>
<urlset
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -45,13 +47,29 @@ header = """<?xml version="1.0" encoding="UTF-8"?>
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
"""
-url_format = """ <url>
+loc_format = """ <url>
<loc>{0}</loc>
<lastmod>{1}</lastmod>
</url>
"""
-get_lastmod = lambda p: datetime.datetime.fromtimestamp(os.stat(p).st_mtime).isoformat().split('T')[0]
+urlset_footer = "</urlset>"
+
+sitemapindex_header = """<?xml version="1.0" encoding="UTF-8"?>
+<sitemapindex
+ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
+ http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
+"""
+
+sitemap_format = """ <sitemap>
+ <loc>{0}</loc>
+ <lastmod>{1}</lastmod>
+ </sitemap>
+"""
+
+sitemapindex_footer = "</sitemapindex>"
def get_base_path(base):
@@ -80,12 +98,12 @@ def get_base_path(base):
class Sitemap(LateTask):
- """Generate google sitemap."""
+ """Generate a sitemap."""
name = "sitemap"
def gen_tasks(self):
- """Generate Google sitemap."""
+ """Generate a sitemap."""
kw = {
"base_url": self.site.config["BASE_URL"],
"site_url": self.site.config["SITE_URL"],
@@ -93,28 +111,32 @@ class Sitemap(LateTask):
"strip_indexes": self.site.config["STRIP_INDEXES"],
"index_file": self.site.config["INDEX_FILE"],
"sitemap_include_fileless_dirs": self.site.config["SITEMAP_INCLUDE_FILELESS_DIRS"],
- "mapped_extensions": self.site.config.get('MAPPED_EXTENSIONS', ['.html', '.htm', '.xml'])
+ "mapped_extensions": self.site.config.get('MAPPED_EXTENSIONS', ['.html', '.htm', '.xml', '.rss']),
+ "robots_exclusions": self.site.config["ROBOTS_EXCLUSIONS"]
}
- output_path = kw['output_folder']
- sitemap_path = os.path.join(output_path, "sitemap.xml")
- base_path = get_base_path(kw['base_url'])
- locs = {}
output = kw['output_folder']
base_url = kw['base_url']
mapped_exts = kw['mapped_extensions']
+ output_path = kw['output_folder']
+ sitemapindex_path = os.path.join(output_path, "sitemapindex.xml")
+ sitemap_path = os.path.join(output_path, "sitemap.xml")
+ base_path = get_base_path(kw['base_url'])
+ sitemapindex = {}
+ urlset = {}
+
def scan_locs():
- for root, dirs, files in os.walk(output):
+ for root, dirs, files in os.walk(output, followlinks=True):
if not dirs and not files and not kw['sitemap_include_fileless_dirs']:
continue # Totally empty, not on sitemap
path = os.path.relpath(root, output)
# ignore the current directory.
path = (path.replace(os.sep, '/') + '/').replace('./', '')
- lastmod = get_lastmod(root)
+ lastmod = self.get_lastmod(root)
loc = urljoin(base_url, base_path + path)
if kw['index_file'] in files and kw['strip_indexes']: # ignore folders when not stripping urls
- locs[loc] = url_format.format(loc, lastmod)
+ urlset[loc] = loc_format.format(loc, lastmod)
for fname in files:
if kw['strip_indexes'] and fname == kw['index_file']:
continue # We already mapped the folder
@@ -124,38 +146,68 @@ class Sitemap(LateTask):
if path.endswith(kw['index_file']) and kw['strip_indexes']:
# ignore index files when stripping urls
continue
+ if not robot_fetch(path):
+ continue
if path.endswith('.html') or path.endswith('.htm'):
- if not u'<!doctype html' in codecs.open(real_path, 'r', 'utf8').read(1024).lower():
- # ignores "html" files without doctype
- # alexa-verify, google-site-verification, etc.
+ try:
+ if u'<!doctype html' not in codecs.open(real_path, 'r', 'utf8').read(1024).lower():
+ # ignores "html" files without doctype
+ # alexa-verify, google-site-verification, etc.
+ continue
+ except UnicodeDecodeError:
+ # ignore ancient files
+ # most non-utf8 files are worthless anyways
continue
- if path.endswith('.xml'):
- if not u'<rss' in codecs.open(real_path, 'r', 'utf8').read(512):
- # ignores all XML files except those presumed to be RSS
+ """ put RSS in sitemapindex[] instead of in urlset[], sitemap_path is included after it is generated """
+ if path.endswith('.xml') or path.endswith('.rss'):
+ if u'<rss' in codecs.open(real_path, 'r', 'utf8').read(512) or u'<urlset'and path != sitemap_path:
+ path = path.replace(os.sep, '/')
+ lastmod = self.get_lastmod(real_path)
+ loc = urljoin(base_url, base_path + path)
+ sitemapindex[loc] = sitemap_format.format(loc, lastmod)
continue
+ else:
+ continue # ignores all XML files except those presumed to be RSS
post = self.site.post_per_file.get(path)
- if post and (post.is_draft or post.is_retired or post.publish_later):
+ if post and (post.is_draft or post.is_private or post.publish_later):
continue
path = path.replace(os.sep, '/')
- lastmod = get_lastmod(real_path)
+ lastmod = self.get_lastmod(real_path)
loc = urljoin(base_url, base_path + path)
- locs[loc] = url_format.format(loc, lastmod)
+ urlset[loc] = loc_format.format(loc, lastmod)
+
+ def robot_fetch(path):
+ for rule in kw["robots_exclusions"]:
+ robot = robotparser.RobotFileParser()
+ robot.parse(["User-Agent: *", "Disallow: {0}".format(rule)])
+ if not robot.can_fetch("*", '/' + path):
+ return False # not robot food
+ return True
def write_sitemap():
# Have to rescan, because files may have been added between
# task dep scanning and task execution
with codecs.open(sitemap_path, 'wb+', 'utf8') as outf:
- outf.write(header)
- for k in sorted(locs.keys()):
- outf.write(locs[k])
- outf.write("</urlset>")
+ outf.write(urlset_header)
+ for k in sorted(urlset.keys()):
+ outf.write(urlset[k])
+ outf.write(urlset_footer)
+ sitemap_url = urljoin(base_url, base_path + "sitemap.xml")
+ sitemapindex[sitemap_url] = sitemap_format.format(sitemap_url, self.get_lastmod(sitemap_path))
+
+ def write_sitemapindex():
+ with codecs.open(sitemapindex_path, 'wb+', 'utf8') as outf:
+ outf.write(sitemapindex_header)
+ for k in sorted(sitemapindex.keys()):
+ outf.write(sitemapindex[k])
+ outf.write(sitemapindex_footer)
# Yield a task to calculate the dependencies of the sitemap
# Other tasks can depend on this output, instead of having
# to scan locations.
def scan_locs_task():
scan_locs()
- return {'locations': list(locs.keys())}
+ return {'locations': list(urlset.keys()) + list(sitemapindex.keys())}
yield {
"basename": "_scan_locs",
@@ -164,7 +216,7 @@ class Sitemap(LateTask):
}
yield self.group_task()
- task = {
+ yield {
"basename": "sitemap",
"name": sitemap_path,
"targets": [sitemap_path],
@@ -174,7 +226,21 @@ class Sitemap(LateTask):
"task_dep": ["render_site"],
"calc_dep": ["_scan_locs:sitemap"],
}
- yield task
+ yield {
+ "basename": "sitemap",
+ "name": sitemapindex_path,
+ "targets": [sitemapindex_path],
+ "actions": [(write_sitemapindex,)],
+ "uptodate": [config_changed(kw)],
+ "clean": True,
+ "file_dep": [sitemap_path]
+ }
+
+ def get_lastmod(self, p):
+ if self.site.invariant:
+ return '2014-01-01'
+ else:
+ return datetime.datetime.fromtimestamp(os.stat(p).st_mtime).isoformat().split('T')[0]
if __name__ == '__main__':
import doctest
diff --git a/nikola/plugins/task/tags.py b/nikola/plugins/task/tags.py
index f6b8234..f7f3579 100644
--- a/nikola/plugins/task/tags.py
+++ b/nikola/plugins/task/tags.py
@@ -61,12 +61,14 @@ class RenderTags(Task):
"output_folder": self.site.config['OUTPUT_FOLDER'],
"filters": self.site.config['FILTERS'],
"tag_pages_are_indexes": self.site.config['TAG_PAGES_ARE_INDEXES'],
- "index_display_post_count":
- self.site.config['INDEX_DISPLAY_POST_COUNT'],
+ "index_display_post_count": self.site.config['INDEX_DISPLAY_POST_COUNT'],
"index_teasers": self.site.config['INDEX_TEASERS'],
+ "generate_rss": self.site.config['GENERATE_RSS'],
"rss_teasers": self.site.config["RSS_TEASERS"],
- "hide_untranslated_posts": self.site.config['HIDE_UNTRANSLATED_POSTS'],
+ "rss_plain": self.site.config["RSS_PLAIN"],
+ "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
"feed_length": self.site.config['FEED_LENGTH'],
+ "tzinfo": self.site.tzinfo,
}
self.site.scan_posts()
@@ -81,16 +83,15 @@ class RenderTags(Task):
cat_list = list(self.site.posts_per_category.items())
def render_lists(tag, posts, is_category=True):
- post_list = [self.site.global_data[post] for post in posts]
- post_list.sort(key=lambda a: a.date)
+ post_list = sorted(posts, key=lambda a: a.date)
post_list.reverse()
for lang in kw["translations"]:
- if kw["hide_untranslated_posts"]:
- filtered_posts = [x for x in post_list if x.is_translation_available(lang)]
- else:
+ if kw["show_untranslated_posts"]:
filtered_posts = post_list
- rss_post_list = [p.source_path for p in filtered_posts]
- yield self.tag_rss(tag, lang, rss_post_list, kw, is_category)
+ else:
+ filtered_posts = [x for x in post_list if x.is_translation_available(lang)]
+ if kw["generate_rss"]:
+ yield self.tag_rss(tag, lang, filtered_posts, kw, is_category)
# Render HTML
if kw['tag_pages_are_indexes']:
yield self.tag_page_as_index(tag, lang, filtered_posts, kw, is_category)
@@ -205,12 +206,13 @@ class RenderTags(Task):
num_pages = len(lists)
for i, post_list in enumerate(lists):
context = {}
- # On a tag page, the feeds include the tag's feeds
- rss_link = ("""<link rel="alternate" type="application/rss+xml" """
- """type="application/rss+xml" title="RSS for tag """
- """{0} ({1})" href="{2}">""".format(
- tag, lang, self.site.link(kind + "_rss", tag, lang)))
- context['rss_link'] = rss_link
+ if kw["generate_rss"]:
+ # On a tag page, the feeds include the tag's feeds
+ rss_link = ("""<link rel="alternate" type="application/rss+xml" """
+ """type="application/rss+xml" title="RSS for tag """
+ """{0} ({1})" href="{2}">""".format(
+ tag, lang, self.site.link(kind + "_rss", tag, lang)))
+ context['rss_link'] = rss_link
output_name = os.path.join(kw['output_folder'],
page_name(tag, i, lang))
context["title"] = kw["messages"][lang][
@@ -274,15 +276,13 @@ class RenderTags(Task):
def tag_rss(self, tag, lang, posts, kw, is_category):
"""RSS for a single tag / language"""
kind = "category" if is_category else "tag"
- #Render RSS
+ # Render RSS
output_name = os.path.normpath(
os.path.join(kw['output_folder'],
self.site.path(kind + "_rss", tag, lang)))
feed_url = urljoin(self.site.config['BASE_URL'], self.site.link(kind + "_rss", tag, lang).lstrip('/'))
deps = []
- post_list = [self.site.global_data[post] for post in posts if
- self.site.global_data[post].use_in_feeds]
- post_list.sort(key=lambda a: a.date)
+ post_list = sorted(posts, key=lambda a: a.date)
post_list.reverse()
for post in post_list:
deps += post.deps(lang)
@@ -292,9 +292,10 @@ class RenderTags(Task):
'file_dep': deps,
'targets': [output_name],
'actions': [(utils.generic_rss_renderer,
- (lang, "{0} ({1})".format(kw["blog_title"], tag),
+ (lang, "{0} ({1})".format(kw["blog_title"](lang), tag),
kw["site_url"], None, post_list,
- output_name, kw["rss_teasers"], kw['feed_length'], feed_url))],
+ output_name, kw["rss_teasers"], kw["rss_plain"], kw['feed_length'],
+ feed_url))],
'clean': True,
'uptodate': [utils.config_changed(kw)],
'task_dep': ['render_posts'],
diff --git a/nikola/plugins/template/jinja.py b/nikola/plugins/template/jinja.py
index f14adfe..097ec96 100644
--- a/nikola/plugins/template/jinja.py
+++ b/nikola/plugins/template/jinja.py
@@ -51,6 +51,8 @@ class JinjaTemplates(TemplateSystem):
if jinja2 is None:
return
self.lookup = jinja2.Environment()
+ self.lookup.trim_blocks = True
+ self.lookup.lstrip_blocks = True
self.lookup.filters['tojson'] = json.dumps
self.lookup.globals['enumerate'] = enumerate
@@ -58,7 +60,19 @@ class JinjaTemplates(TemplateSystem):
"""Create a template lookup."""
if jinja2 is None:
req_missing(['jinja2'], 'use this theme')
- self.lookup.loader = jinja2.FileSystemLoader(directories,
+ self.directories = directories
+ self.create_lookup()
+
+ def inject_directory(self, directory):
+ """if it's not there, add the directory to the lookup with lowest priority, and
+ recreate the lookup."""
+ if directory not in self.directories:
+ self.directories.append(directory)
+ self.create_lookup()
+
+ def create_lookup(self):
+ """Create a template lookup object."""
+ self.lookup.loader = jinja2.FileSystemLoader(self.directories,
encoding='utf-8')
def set_site(self, site):
diff --git a/nikola/plugins/template/mako.py b/nikola/plugins/template/mako.py
index 5a23230..b9d856e 100644
--- a/nikola/plugins/template/mako.py
+++ b/nikola/plugins/template/mako.py
@@ -50,6 +50,8 @@ class MakoTemplates(TemplateSystem):
lookup = None
cache = {}
filters = {}
+ directories = []
+ cache_dir = None
def get_deps(self, filename):
text = util.read_file(filename)
@@ -65,7 +67,7 @@ class MakoTemplates(TemplateSystem):
return deps
def set_directories(self, directories, cache_folder):
- """Create a template lookup."""
+ """Set directories and create a template lookup."""
cache_dir = os.path.join(cache_folder, '.mako.tmp')
# Workaround for a Mako bug, Issue #825
if sys.version_info[0] == 2:
@@ -74,12 +76,24 @@ class MakoTemplates(TemplateSystem):
except UnicodeEncodeError:
cache_dir = tempfile.mkdtemp()
LOGGER.warning('Because of a Mako bug, setting cache_dir to {0}'.format(cache_dir))
-
if os.path.exists(cache_dir):
shutil.rmtree(cache_dir)
+ self.directories = directories
+ self.cache_dir = cache_dir
+ self.create_lookup()
+
+ def inject_directory(self, directory):
+ """if it's not there, add the directory to the lookup with lowest priority, and
+ recreate the lookup."""
+ if directory not in self.directories:
+ self.directories.append(directory)
+ self.create_lookup()
+
+ def create_lookup(self):
+ """Create a template lookup object."""
self.lookup = TemplateLookup(
- directories=directories,
- module_directory=cache_dir,
+ directories=self.directories,
+ module_directory=self.cache_dir,
output_encoding='utf-8')
def set_site(self, site):
diff --git a/nikola/post.py b/nikola/post.py
index 5cf7236..3e3b608 100644
--- a/nikola/post.py
+++ b/nikola/post.py
@@ -37,12 +37,15 @@ try:
except ImportError:
from urllib.parse import urljoin # NOQA
+import dateutil.tz
import lxml.html
+import natsort
try:
import pyphen
except ImportError:
pyphen = None
-import pytz
+
+from math import ceil
# for tearDown with _reload we cannot use 'from import' to get forLocaleBorg
import nikola.utils
@@ -51,18 +54,19 @@ from .utils import (
current_time,
Functionary,
LOGGER,
+ LocaleBorg,
slugify,
to_datetime,
unicode_str,
demote_headers,
get_translation_candidate,
+ unslugify,
)
from .rc4 import rc4
__all__ = ['Post']
TEASER_REGEXP = re.compile('<!--\s*TEASER_END(:(.+))?\s*-->', re.IGNORECASE)
-READ_MORE_LINK = '<p class="more"><a href="{link}">{read_more}…</a></p>'
class Post(object):
@@ -89,17 +93,17 @@ class Post(object):
self.compiler = compiler
self.compile_html = self.compiler.compile_html
self.demote_headers = self.compiler.demote_headers and self.config['DEMOTE_HEADERS']
- tzinfo = pytz.timezone(self.config['TIMEZONE'])
+ tzinfo = self.config['__tzinfo__']
if self.config['FUTURE_IS_NOW']:
self.current_time = None
else:
- self.current_time = current_time(tzinfo)
+ self.current_time = current_time()
self.translated_to = set([])
self._prev_post = None
self._next_post = None
self.base_url = self.config['BASE_URL']
self.is_draft = False
- self.is_retired = False
+ self.is_private = False
self.is_mathjax = False
self.strip_indexes = self.config['STRIP_INDEXES']
self.index_file = self.config['INDEX_FILE']
@@ -115,29 +119,29 @@ class Post(object):
self.translations = self.config['TRANSLATIONS']
self.default_lang = self.config['DEFAULT_LANG']
self.messages = messages
- self.skip_untranslated = self.config['HIDE_UNTRANSLATED_POSTS']
+ self.skip_untranslated = not self.config['SHOW_UNTRANSLATED_POSTS']
self._template_name = template_name
self.is_two_file = True
self.hyphenate = self.config['HYPHENATE']
self._reading_time = None
+ self._remaining_reading_time = None
+ self._paragraph_count = None
+ self._remaining_paragraph_count = None
- default_metadata = get_meta(self, self.config['FILE_METADATA_REGEXP'])
+ default_metadata = get_meta(self, self.config['FILE_METADATA_REGEXP'], self.config['UNSLUGIFY_TITLES'])
self.meta = Functionary(lambda: None, self.default_lang)
self.meta[self.default_lang] = default_metadata
# Load internationalized metadata
for lang in self.translations:
+ if os.path.isfile(get_translation_candidate(self.config, self.source_path, lang)):
+ self.translated_to.add(lang)
if lang != self.default_lang:
- if os.path.isfile(get_translation_candidate(self.config, self.source_path, lang)):
- self.translated_to.add(lang)
-
meta = defaultdict(lambda: '')
meta.update(default_metadata)
- meta.update(get_meta(self, self.config['FILE_METADATA_REGEXP'], lang))
+ meta.update(get_meta(self, self.config['FILE_METADATA_REGEXP'], self.config['UNSLUGIFY_TITLES'], lang))
self.meta[lang] = meta
- elif os.path.isfile(self.source_path):
- self.translated_to.add(self.default_lang)
if not self.is_translation_available(self.default_lang):
# Special case! (Issue #373)
@@ -147,8 +151,11 @@ class Post(object):
if 'date' not in default_metadata and not use_in_feeds:
# For stories we don't *really* need a date
- default_metadata['date'] = datetime.datetime.utcfromtimestamp(
- os.stat(self.source_path).st_ctime).replace(tzinfo=pytz.UTC).astimezone(tzinfo)
+ if self.config['__invariant__']:
+ default_metadata['date'] = datetime.datetime(2013, 12, 31, 23, 59, 59, tzinfo=tzinfo)
+ else:
+ default_metadata['date'] = datetime.datetime.utcfromtimestamp(
+ os.stat(self.source_path).st_ctime).replace(tzinfo=dateutil.tz.tzutc()).astimezone(tzinfo)
if 'title' not in default_metadata or 'slug' not in default_metadata \
or 'date' not in default_metadata:
@@ -169,26 +176,34 @@ class Post(object):
self.publish_later = False if self.current_time is None else self.date >= self.current_time
is_draft = False
- is_retired = False
+ is_private = False
self._tags = {}
for lang in self.translated_to:
- self._tags[lang] = [x.strip() for x in self.meta[lang]['tags'].split(',')]
+ self._tags[lang] = natsort.natsorted(
+ list(set([x.strip() for x in self.meta[lang]['tags'].split(',')])))
self._tags[lang] = [t for t in self._tags[lang] if t]
if 'draft' in self._tags[lang]:
is_draft = True
+ LOGGER.debug('The post "{0}" is a draft.'.format(self.source_path))
self._tags[lang].remove('draft')
+
+ # TODO: remove in v8
if 'retired' in self._tags[lang]:
- is_retired = True
+ is_private = True
+ LOGGER.warning('The "retired" tag in post "{0}" is now deprecated and will be removed in v8. Use "private" instead.'.format(self.source_path))
self._tags[lang].remove('retired')
+ # end remove in v8
+
if 'private' in self._tags[lang]:
- is_retired = True
+ is_private = True
+ LOGGER.debug('The post "{0}" is private.'.format(self.source_path))
self._tags[lang].remove('private')
# While draft comes from the tags, it's not really a tag
self.is_draft = is_draft
- self.is_retired = is_retired
+ self.is_private = is_private
self.is_post = use_in_feeds
- self.use_in_feeds = use_in_feeds and not is_draft and not is_retired \
+ self.use_in_feeds = use_in_feeds and not is_draft and not is_private \
and not self.publish_later
# If mathjax is a tag, then enable mathjax rendering support
@@ -277,6 +292,21 @@ class Post(object):
lang = nikola.utils.LocaleBorg().current_lang
return self.meta[lang]['title']
+ def author(self, lang=None):
+ """Return localized author or BLOG_AUTHOR if unspecified.
+
+ If lang is not specified, it defaults to the current language from
+ templates, as set in LocaleBorg.
+ """
+ if lang is None:
+ lang = nikola.utils.LocaleBorg().current_lang
+ if self.meta[lang]['author']:
+ author = self.meta[lang]['author']
+ else:
+ author = self.config['BLOG_AUTHOR'](lang)
+
+ return author
+
def description(self, lang=None):
"""Return localized description."""
if lang is None:
@@ -290,7 +320,6 @@ class Post(object):
deps.append(self.base_path)
if lang != self.default_lang:
deps += [get_translation_candidate(self.config, self.base_path, lang)]
- deps += self.fragment_deps(lang)
return deps
def compile(self, lang):
@@ -304,21 +333,31 @@ class Post(object):
with codecs.open(path, 'wb+', 'utf8') as outf:
outf.write(data)
- self.READ_MORE_LINK = self.config['READ_MORE_LINK']
dest = self.translated_base_path(lang)
- if not self.is_translation_available(lang) and self.config['HIDE_UNTRANSLATED_POSTS']:
+ if not self.is_translation_available(lang) and not self.config['SHOW_UNTRANSLATED_POSTS']:
return
- else:
- self.compile_html(
- self.translated_source_path(lang),
- dest,
- self.is_two_file),
+ # Set the language to the right thing
+ LocaleBorg().set_locale(lang)
+ self.compile_html(
+ self.translated_source_path(lang),
+ dest,
+ self.is_two_file),
if self.meta('password'):
wrap_encrypt(dest, self.meta('password'))
if self.publish_later:
LOGGER.notice('{0} is scheduled to be published in the future ({1})'.format(
self.source_path, self.date))
+ def extra_deps(self):
+ """get extra depepencies from .dep files
+ This file is created by ReST
+ """
+ dep_path = self.base_path + '.dep'
+ if os.path.isfile(dep_path):
+ with codecs.open(dep_path, 'rb+', 'utf8') as depf:
+ return [l.strip() for l in depf.readlines()]
+ return []
+
def fragment_deps(self, lang):
"""Return a list of dependencies to build this post's fragment."""
deps = []
@@ -326,10 +365,7 @@ class Post(object):
deps.append(self.source_path)
if os.path.isfile(self.metadata_path):
deps.append(self.metadata_path)
- dep_path = self.base_path + '.dep'
- if os.path.isfile(dep_path):
- with codecs.open(dep_path, 'rb+', 'utf8') as depf:
- deps.extend([l.strip() for l in depf.readlines()])
+ deps.extend(self.extra_deps())
lang_deps = []
if lang != self.default_lang:
lang_deps = [get_translation_candidate(self.config, d, lang) for d in deps]
@@ -354,10 +390,7 @@ class Post(object):
def translated_base_path(self, lang):
"""Return path to the translation's base_path file."""
- if lang == self.default_lang:
- return self.base_path
- else:
- return get_translation_candidate(self.config, self.base_path, lang)
+ return get_translation_candidate(self.config, self.base_path, lang)
def _translated_file_path(self, lang):
"""Return path to the translation's file, or to the original."""
@@ -371,16 +404,30 @@ class Post(object):
else:
return get_translation_candidate(self.config, self.base_path, sorted(self.translated_to)[0])
- def text(self, lang=None, teaser_only=False, strip_html=False, really_absolute=False):
+ def text(self, lang=None, teaser_only=False, strip_html=False, show_read_more_link=True, rss_read_more_link=False):
"""Read the post file for that language and return its contents.
teaser_only=True breaks at the teaser marker and returns only the teaser.
strip_html=True removes HTML tags
+ show_read_more_link=False does not add the Read more... link
+ rss_read_more_link=True uses RSS_READ_MORE_LINK instead of INDEX_READ_MORE_LINK
lang=None uses the last used to set locale
All links in the returned HTML will be relative.
The HTML returned is a bare fragment, not a full document.
"""
+ def strip_root_element(el):
+ ''' Strips root tag from an Element.
+
+ Required because lxml has an tendency to add <div>, <body>
+ root tags to strings which are generated by using
+ lxml.html.tostring()
+
+ :param Element el: the root element to strip
+ '''
+ return (el.text or '') + ''.join(
+ [lxml.html.tostring(child, encoding='unicode')
+ for child in el.iterchildren()])
if lang is None:
lang = nikola.utils.LocaleBorg().current_lang
@@ -395,7 +442,7 @@ class Post(object):
return ""
# let other errors raise
raise(e)
- base_url = self.permalink(lang=lang, absolute=really_absolute)
+ base_url = self.permalink(lang=lang)
document.make_links_absolute(base_url)
if self.hyphenate:
@@ -405,28 +452,34 @@ class Post(object):
# data here is a full HTML doc, including HTML and BODY tags
# which is not ideal (Issue #464)
try:
- body = document.body
- data = (body.text or '') + ''.join(
- [lxml.html.tostring(child, encoding='unicode')
- for child in body.iterchildren()])
+ data = strip_root_element(document.body)
except IndexError: # No body there, it happens sometimes
pass
if teaser_only:
teaser = TEASER_REGEXP.split(data)[0]
if teaser != data:
- if not strip_html:
+ if not strip_html and show_read_more_link:
if TEASER_REGEXP.search(data).groups()[-1]:
teaser += '<p class="more"><a href="{0}">{1}</a></p>'.format(
- self.permalink(lang, absolute=really_absolute),
+ self.permalink(lang),
TEASER_REGEXP.search(data).groups()[-1])
else:
- teaser += READ_MORE_LINK.format(
- link=self.permalink(lang, absolute=really_absolute),
- read_more=self.messages[lang]["Read more"])
+ l = self.config['RSS_READ_MORE_LINK'](lang) if rss_read_more_link else self.config['INDEX_READ_MORE_LINK'](lang)
+ teaser += l.format(
+ link=self.permalink(lang),
+ read_more=self.messages[lang]["Read more"],
+ min_remaining_read=self.messages[lang]["%d min remaining to read"] % (self.remaining_reading_time),
+ reading_time=self.reading_time,
+ remaining_reading_time=self.remaining_reading_time,
+ paragraph_count=self.paragraph_count,
+ remaining_paragraph_count=self.remaining_paragraph_count)
# This closes all open tags and sanitizes the broken HTML
document = lxml.html.fromstring(teaser)
- data = lxml.html.tostring(document, encoding='unicode')
+ try:
+ data = strip_root_element(document)
+ except IndexError:
+ data = lxml.html.tostring(document, encoding='unicode')
if data and strip_html:
try:
@@ -441,23 +494,71 @@ class Post(object):
try:
document = lxml.html.fromstring(data)
demote_headers(document, self.demote_headers)
+ data = strip_root_element(document)
+ except (lxml.etree.ParserError, IndexError):
data = lxml.html.tostring(document, encoding='unicode')
- except lxml.etree.ParserError:
- pass
return data
@property
def reading_time(self):
- """Reading time based on length of text.
- """
+ """Reading time based on length of text."""
if self._reading_time is None:
text = self.text(strip_html=True)
- words_per_minute = 180
+ words_per_minute = 220
words = len(text.split())
- self._reading_time = int(round(words / words_per_minute)) or 1
+ self._reading_time = int(ceil(words / words_per_minute)) or 1
return self._reading_time
+ @property
+ def remaining_reading_time(self):
+ """Remaining reading time based on length of text (does not include teaser)."""
+ if self._remaining_reading_time is None:
+ text = self.text(teaser_only=True, strip_html=True)
+ words_per_minute = 220
+ words = len(text.split())
+ self._remaining_reading_time = self.reading_time - int(ceil(words / words_per_minute)) or 1
+ return self._remaining_reading_time
+
+ @property
+ def paragraph_count(self):
+ """Return the paragraph count for this post."""
+ if self._paragraph_count is None:
+ # duplicated with Post.text()
+ lang = nikola.utils.LocaleBorg().current_lang
+ file_name = self._translated_file_path(lang)
+ with codecs.open(file_name, "r", "utf8") as post_file:
+ data = post_file.read().strip()
+ try:
+ document = lxml.html.fragment_fromstring(data, "body")
+ except lxml.etree.ParserError as e:
+ # if we don't catch this, it breaks later (Issue #374)
+ if str(e) == "Document is empty":
+ return ""
+ # let other errors raise
+ raise(e)
+
+ # output is a float, for no real reason at all
+ self._paragraph_count = int(document.xpath('count(//p)'))
+ return self._paragraph_count
+
+ @property
+ def remaining_paragraph_count(self):
+ """Return the remaining paragraph count for this post (does not include teaser)."""
+ if self._remaining_paragraph_count is None:
+ try:
+ # Just asking self.text() is easier here.
+ document = lxml.html.fragment_fromstring(self.text(teaser_only=True, show_read_more_link=False), "body")
+ except lxml.etree.ParserError as e:
+ # if we don't catch this, it breaks later (Issue #374)
+ if str(e) == "Document is empty":
+ return ""
+ # let other errors raise
+ raise(e)
+
+ self._remaining_paragraph_count = self.paragraph_count - int(document.xpath('count(//p)'))
+ return self._remaining_paragraph_count
+
def source_link(self, lang=None):
"""Return absolute link to the post's source."""
return "/" + self.destination_path(
@@ -524,7 +625,7 @@ def re_meta(line, match=None):
return (None,)
-def _get_metadata_from_filename_by_regex(filename, metadata_regexp):
+def _get_metadata_from_filename_by_regex(filename, metadata_regexp, unslugify_titles):
"""
Tries to ried the metadata from the filename based on the given re.
This requires to use symbolic group names in the pattern.
@@ -538,7 +639,11 @@ def _get_metadata_from_filename_by_regex(filename, metadata_regexp):
if match:
# .items() for py3k compat.
for key, value in match.groupdict().items():
- meta[key.lower()] = value # metadata must be lowercase
+ k = key.lower().strip() # metadata must be lowercase
+ if k == 'title' and unslugify_titles:
+ meta[k] = unslugify(value, discard_numbers=False)
+ else:
+ meta[k] = value
return meta
@@ -620,29 +725,43 @@ def get_metadata_from_meta_file(path, config=None, lang=None):
if os.path.isfile(meta_path):
with codecs.open(meta_path, "r", "utf8") as meta_file:
meta_data = meta_file.readlines()
- while len(meta_data) < 7:
- meta_data.append("")
- (title, slug, date, tags, link, description, _type) = [
- x.strip() for x in meta_data][:7]
-
- meta = {}
-
- if title:
- meta['title'] = title
- if slug:
- meta['slug'] = slug
- if date:
- meta['date'] = date
- if tags:
- meta['tags'] = tags
- if link:
- meta['link'] = link
- if description:
- meta['description'] = description
- if _type:
- meta['type'] = _type
- return meta
+ # Detect new-style metadata.
+ newstyleregexp = re.compile(r'\.\. .*?: .*')
+ newstylemeta = False
+ for l in meta_data:
+ if l.strip():
+ if re.match(newstyleregexp, l):
+ newstylemeta = True
+
+ if newstylemeta:
+ # New-style metadata is basically the same as reading metadata from
+ # a 1-file post.
+ return get_metadata_from_file(path, config, lang)
+ else:
+ while len(meta_data) < 7:
+ meta_data.append("")
+ (title, slug, date, tags, link, description, _type) = [
+ x.strip() for x in meta_data][:7]
+
+ meta = {}
+
+ if title:
+ meta['title'] = title
+ if slug:
+ meta['slug'] = slug
+ if date:
+ meta['date'] = date
+ if tags:
+ meta['tags'] = tags
+ if link:
+ meta['link'] = link
+ if description:
+ meta['description'] = description
+ if _type:
+ meta['type'] = _type
+
+ return meta
elif lang:
# Metadata file doesn't exist, but not default language,
@@ -653,11 +772,12 @@ def get_metadata_from_meta_file(path, config=None, lang=None):
return {}
-def get_meta(post, file_metadata_regexp=None, lang=None):
+def get_meta(post, file_metadata_regexp=None, unslugify_titles=False, lang=None):
"""Get post's meta from source.
If ``file_metadata_regexp`` is given it will be tried to read
metadata from the filename.
+ If ``unslugify_titles`` is True, the extracted title (if any) will be unslugified, as is done in galleries.
If any metadata is then found inside the file the metadata from the
file will override previous findings.
"""
@@ -676,7 +796,8 @@ def get_meta(post, file_metadata_regexp=None, lang=None):
if file_metadata_regexp is not None:
meta.update(_get_metadata_from_filename_by_regex(post.source_path,
- file_metadata_regexp))
+ file_metadata_regexp,
+ unslugify_titles))
meta.update(get_metadata_from_file(post.source_path, config, lang))
diff --git a/nikola/utils.py b/nikola/utils.py
index 46e159e..9420595 100644
--- a/nikola/utils.py
+++ b/nikola/utils.py
@@ -26,10 +26,11 @@
"""Utility functions."""
-from __future__ import print_function, unicode_literals
+from __future__ import print_function, unicode_literals, absolute_import
from collections import defaultdict, Callable
import calendar
import datetime
+import dateutil.tz
import hashlib
import locale
import logging
@@ -39,17 +40,18 @@ import json
import shutil
import subprocess
import sys
-from zipfile import ZipFile as zip
+from zipfile import ZipFile as zipf
try:
from imp import reload
except ImportError:
pass
+import dateutil.parser
+import dateutil.tz
import logbook
from logbook.more import ExceptionHandler, ColorizedStderrHandler
-import pytz
-from . import DEBUG
+from nikola import DEBUG
class ApplicationWarning(Exception):
@@ -70,29 +72,65 @@ def get_logger(name, handlers):
l = logbook.Logger(name)
for h in handlers:
if isinstance(h, list):
- l.handlers += h
+ l.handlers = h
else:
- l.handlers.append(h)
+ l.handlers = [h]
return l
STDERR_HANDLER = [ColorfulStderrHandler(
- level=logbook.NOTICE if not DEBUG else logbook.DEBUG,
+ level=logbook.INFO if not DEBUG else logbook.DEBUG,
format_string=u'[{record.time:%Y-%m-%dT%H:%M:%SZ}] {record.level_name}: {record.channel}: {record.message}'
)]
LOGGER = get_logger('Nikola', STDERR_HANDLER)
STRICT_HANDLER = ExceptionHandler(ApplicationWarning, level='WARNING')
+# This will block out the default handler and will hide all unwanted
+# messages, properly.
+logbook.NullHandler().push_application()
+
if DEBUG:
logging.basicConfig(level=logging.DEBUG)
else:
- logging.basicConfig(level=logging.WARNING)
+ logging.basicConfig(level=logging.INFO)
+
+
+import warnings
+
+
+def showwarning(message, category, filename, lineno, file=None, line=None):
+ """Show a warning (from the warnings subsystem) to the user."""
+ try:
+ n = category.__name__
+ except AttributeError:
+ n = str(category)
+ get_logger(n, STDERR_HANDLER).warn('{0}:{1}: {2}'.format(filename, lineno, message))
+
+warnings.showwarning = showwarning
def req_missing(names, purpose, python=True, optional=False):
- """Log that we are missing some requirements."""
+ """Log that we are missing some requirements.
+
+ `names` is a list/tuple/set of missing things.
+ `purpose` is a string, specifying the use of the missing things.
+ It completes the sentence:
+ In order to {purpose}, you must install ...
+ `python` specifies whether the requirements are Python packages
+ or other software.
+ `optional` specifies whether the things are required
+ (this is an error and we exit with code 5)
+ or not (this is just a warning).
+
+ Returns the message shown to the user (which you can usually discard).
+ If no names are specified, False is returned and nothing is shown
+ to the user.
+
+ """
if not (isinstance(names, tuple) or isinstance(names, list) or isinstance(names, set)):
names = (names,)
+ if not names:
+ return False
if python:
whatarethey_s = 'Python package'
whatarethey_p = 'Python packages'
@@ -121,6 +159,7 @@ if sys.version_info[0] == 3:
bytes_str = bytes
unicode_str = str
unichr = chr
+ raw_input = input
from imp import reload as _reload
else:
bytes_str = str
@@ -130,6 +169,7 @@ else:
from doit import tools
from unidecode import unidecode
+from pkg_resources import resource_filename
import PyRSS2Gen as rss
@@ -137,9 +177,13 @@ __all__ = ['get_theme_path', 'get_theme_chain', 'load_messages', 'copy_tree',
'copy_file', 'slugify', 'unslugify', 'to_datetime', 'apply_filters',
'config_changed', 'get_crumbs', 'get_tzname', 'get_asset_path',
'_reload', 'unicode_str', 'bytes_str', 'unichr', 'Functionary',
- 'LocaleBorg', 'sys_encode', 'sys_decode', 'makedirs',
- 'get_parent_theme_name', 'ExtendedRSS2', 'demote_headers',
- 'get_translation_candidate']
+ 'TranslatableSetting', 'TemplateHookRegistry', 'LocaleBorg',
+ 'sys_encode', 'sys_decode', 'makedirs', 'get_parent_theme_name',
+ 'demote_headers', 'get_translation_candidate', 'write_metadata',
+ 'ask', 'ask_yesno']
+
+# Are you looking for 'generic_rss_renderer'?
+# It's defined in nikola.nikola.Nikola (the site object).
ENCODING = sys.getfilesystemencoding() or sys.stdin.encoding
@@ -185,10 +229,256 @@ class Functionary(defaultdict):
return self[lang][key]
+class TranslatableSetting(object):
+
+ """
+ A setting that can be translated.
+
+ You can access it via: SETTING(lang). You can omit lang, in which
+ case Nikola will ask LocaleBorg, unless you set SETTING.lang,
+ which overrides that call.
+
+ You can also stringify the setting and you will get something
+ sensible (in what LocaleBorg claims the language is, can also be
+ overriden by SETTING.lang). Note that this second method is
+ deprecated. It is kept for backwards compatibility and
+ safety. It is not guaranteed.
+
+ The underlying structure is a defaultdict. The language that
+ is the default value of the dict is provided with __init__().
+ If you need access the underlying dict (you generally don’t,
+ """
+
+ # WARNING: This is generally not used and replaced with a call to
+ # LocaleBorg(). Set this to a truthy value to override that.
+ lang = None
+
+ # Note that this setting is global. DO NOT set on a per-instance basis!
+ default_lang = 'en'
+
+ def __getattribute__(self, attr):
+ """Return attributes, falling back to string attributes."""
+ try:
+ return super(TranslatableSetting, self).__getattribute__(attr)
+ except AttributeError:
+ return self().__getattribute__(attr)
+
+ def __dir__(self):
+ return list(set(self.__dict__).union(set(dir(str))))
+
+ def __init__(self, name, inp, translations):
+ """Initialize a translated setting.
+
+ Valid inputs include:
+
+ * a string -- the same will be used for all languages
+ * a dict ({lang: value}) -- each language will use the value specified;
+ if there is none, default_lang is used.
+
+ """
+ self.name = name
+ self._inp = inp
+ self.translations = translations
+ self.overriden_default = False
+ self.values = defaultdict()
+
+ if isinstance(inp, dict):
+ self.translated = True
+ self.values.update(inp)
+ if self.default_lang not in self.values.keys():
+ self.default_lang = list(self.values.keys())[0]
+ self.overridden_default = True
+ self.values.default_factory = lambda: self.values[self.default_lang]
+ for k in translations.keys():
+ if k not in self.values.keys():
+ self.values[k] = inp[self.default_lang]
+ else:
+ self.translated = False
+ self.values[self.default_lang] = inp
+ self.values.default_factory = lambda: inp
+
+ def get_lang(self):
+ """Return the language that should be used to retrieve settings."""
+ if self.lang:
+ return self.lang
+ elif not self.translated:
+ return self.default_lang
+ else:
+ try:
+ return LocaleBorg().current_lang
+ except AttributeError:
+ return self.default_lang
+
+ def __call__(self, lang=None):
+ """
+ Return the value in the requested language.
+
+ While lang is None, self.lang (currently set language) is used.
+ Otherwise, the standard algorithm is used (see above).
+
+ """
+ if lang is None:
+ return self.values[self.get_lang()]
+ else:
+ return self.values[lang]
+
+ def __str__(self):
+ """Return the value in the currently set language. (deprecated)"""
+ return self.values[self.get_lang()]
+
+ def __unicode__(self):
+ """Return the value in the currently set language. (deprecated)"""
+ return self.values[self.get_lang()]
+
+ def __repr__(self):
+ """Provide a representation for programmers."""
+ return '<TranslatableSetting: {0!r}>'.format(self.name)
+
+ def format(self, *args, **kwargs):
+ """Format ALL the values in the setting the same way."""
+ for l in self.values:
+ self.values[l] = self.values[l].format(*args, **kwargs)
+ self.values.default_factory = lambda: self.values[self.default_lang]
+ return self
+
+ def langformat(self, formats):
+ """Format ALL the values in the setting, on a per-language basis."""
+ if not formats:
+ # Input is empty.
+ return self
+ else:
+ # This is a little tricky.
+ # Basically, we have some things that may very well be dicts. Or
+ # actually, TranslatableSettings in the original unprocessed dict
+ # form. We need to detect them.
+
+ # First off, we need to check what languages we have and what
+ # should we use as the default.
+ keys = list(formats)
+ if self.default_lang in keys:
+ d = formats[self.default_lang]
+ else:
+ d = formats[keys[0]]
+ # Discovering languages of the settings here.
+ langkeys = []
+ for f in formats.values():
+ for a in f[0] + tuple(f[1].values()):
+ if isinstance(a, dict):
+ langkeys += list(a)
+ # Now that we know all this, we go through all the languages we have.
+ allvalues = set(keys + langkeys + list(self.values))
+ for l in allvalues:
+ if l in keys:
+ oargs, okwargs = formats[l]
+ else:
+ oargs, okwargs = d
+
+ args = []
+ kwargs = {}
+
+ for a in oargs:
+ # We create temporary TranslatableSettings and replace the
+ # values with them.
+ if isinstance(a, dict):
+ a = TranslatableSetting('NULL', a)
+ args.append(a(l))
+ else:
+ args.append(a)
+
+ for k, v in okwargs.items():
+ if isinstance(v, dict):
+ v = TranslatableSetting('NULL', v)
+ kwargs.update({k: v(l)})
+ else:
+ kwargs.update({k: v})
+
+ self.values[l] = self.values[l].format(*args, **kwargs)
+ self.values.default_factory = lambda: self.values[self.default_lang]
+
+ return self
+
+ def __getitem__(self, key):
+ """Provide an alternate interface via __getitem__."""
+ return self.values[key]
+
+ def __setitem__(self, key, value):
+ """Set values for translations."""
+ self.values[key] = value
+
+ def __eq__(self, other):
+ """Test whether two TranslatableSettings are equal."""
+ return self.values == other.values
+
+ def __ne__(self, other):
+ """Test whether two TranslatableSettings are inequal."""
+ return self.values != other.values
+
+
+class TemplateHookRegistry(object):
+
+ """
+ A registry for template hooks.
+
+ Usage:
+
+ >>> r = TemplateHookRegistry('foo', None)
+ >>> r.append('Hello!')
+ >>> r.append(lambda x: 'Hello ' + x + '!', False, 'world')
+ >>> str(r()) # str() call is not recommended in real use
+ 'Hello!\\nHello world!'
+ >>>
+ """
+
+ def __init__(self, name, site):
+ """Initialize a hook registry."""
+ self._items = []
+ self.name = name
+ self.site = site
+ self.context = None
+
+ def generate(self):
+ """Generate items."""
+ for c, inp, site, args, kwargs in self._items:
+ if c:
+ if site:
+ kwargs['site'] = self.site
+ kwargs['context'] = self.context
+ yield inp(*args, **kwargs)
+ else:
+ yield inp
+
+ def __call__(self):
+ """Return items, in a string, separated by newlines."""
+ return '\n'.join(self.generate())
+
+ def append(self, inp, wants_site_and_context=False, *args, **kwargs):
+ """
+ Register an item.
+
+ `inp` can be a string or a callable returning one.
+ `wants_site` tells whether there should be a `site` keyword
+ argument provided, for accessing the site.
+
+ Further positional and keyword arguments are passed as-is to the
+ callable.
+
+ `wants_site`, args and kwargs are ignored (but saved!) if `inp`
+ is not callable. Callability of `inp` is determined only once.
+ """
+ c = callable(inp)
+ self._items.append((c, inp, wants_site_and_context, args, kwargs))
+
+ def __hash__(self):
+ return config_changed({self.name: self._items})
+
+ def __str__(self):
+ return '<TemplateHookRegistry: {0}>'.format(self._items)
+
+
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
try:
- return json.JSONEncoder.default(self, obj)
+ return super(CustomEncoder, self).default(obj)
except TypeError:
s = repr(obj).split('0x', 1)[0]
return s
@@ -206,7 +496,9 @@ class config_changed(tools.config_changed):
byte_data = data.encode("utf-8")
else:
byte_data = data
- return hashlib.md5(byte_data).hexdigest()
+ digest = hashlib.md5(byte_data).hexdigest()
+ # LOGGER.debug('{{"{0}": {1}}}'.format(digest, byte_data))
+ return digest
else:
raise Exception('Invalid type of config_changed parameter -- got '
'{0}, must be string or dict'.format(type(
@@ -217,24 +509,23 @@ class config_changed(tools.config_changed):
cls=CustomEncoder))
-def get_theme_path(theme):
+def get_theme_path(theme, _themes_dir='themes'):
"""Given a theme name, returns the path where its files are located.
Looks in ./themes and in the place where themes go when installed.
"""
- dir_name = os.path.join('themes', theme)
+ dir_name = os.path.join(_themes_dir, theme)
if os.path.isdir(dir_name):
return dir_name
- dir_name = os.path.join(os.path.dirname(__file__),
- 'data', 'themes', theme)
+ dir_name = resource_filename('nikola', os.path.join('data', 'themes', theme))
if os.path.isdir(dir_name):
return dir_name
raise Exception("Can't find theme '{0}'".format(theme))
-def get_template_engine(themes):
+def get_template_engine(themes, _themes_dir='themes'):
for theme_name in themes:
- engine_path = os.path.join(get_theme_path(theme_name), 'engine')
+ engine_path = os.path.join(get_theme_path(theme_name, _themes_dir), 'engine')
if os.path.isfile(engine_path):
with open(engine_path) as fd:
return fd.readlines()[0].strip()
@@ -242,20 +533,20 @@ def get_template_engine(themes):
return 'mako'
-def get_parent_theme_name(theme_name):
- parent_path = os.path.join(get_theme_path(theme_name), 'parent')
+def get_parent_theme_name(theme_name, _themes_dir='themes'):
+ parent_path = os.path.join(get_theme_path(theme_name, _themes_dir), 'parent')
if os.path.isfile(parent_path):
with open(parent_path) as fd:
return fd.readlines()[0].strip()
return None
-def get_theme_chain(theme):
+def get_theme_chain(theme, _themes_dir='themes'):
"""Create the full theme inheritance chain."""
themes = [theme]
while True:
- parent = get_parent_theme_name(themes[-1])
+ parent = get_parent_theme_name(themes[-1], _themes_dir)
# Avoid silly loops
if parent is None or parent in themes:
break
@@ -266,6 +557,15 @@ def get_theme_chain(theme):
warned = []
+class LanguageNotFoundError(Exception):
+ def __init__(self, lang, orig):
+ self.lang = lang
+ self.orig = orig
+
+ def __str__(self):
+ return 'cannot find language {0}'.format(self.lang)
+
+
def load_messages(themes, translations, default_lang):
""" Load theme's messages into context.
@@ -281,18 +581,23 @@ def load_messages(themes, translations, default_lang):
sys.path.insert(0, msg_folder)
english = __import__('messages_en')
for lang in list(translations.keys()):
- # If we don't do the reload, the module is cached
- translation = __import__('messages_' + lang)
- reload(translation)
- if sorted(translation.MESSAGES.keys()) !=\
- sorted(english.MESSAGES.keys()) and \
- lang not in warned:
- warned.append(lang)
- LOGGER.warn("Incomplete translation for language "
- "'{0}'.".format(lang))
- messages[lang].update(english.MESSAGES)
- messages[lang].update(translation.MESSAGES)
- del(translation)
+ try:
+ translation = __import__('messages_' + lang)
+ # If we don't do the reload, the module is cached
+ reload(translation)
+ if sorted(translation.MESSAGES.keys()) !=\
+ sorted(english.MESSAGES.keys()) and \
+ lang not in warned:
+ warned.append(lang)
+ LOGGER.warn("Incomplete translation for language "
+ "'{0}'.".format(lang))
+ messages[lang].update(english.MESSAGES)
+ for k, v in translation.MESSAGES.items():
+ if v:
+ messages[lang][k] = v
+ del(translation)
+ except ImportError as orig:
+ raise LanguageNotFoundError(lang, orig)
sys.path = oldpath
return messages
@@ -314,7 +619,7 @@ def copy_tree(src, dst, link_cutoff=None):
"""
ignore = set(['.svn'])
base_len = len(src.split(os.sep))
- for root, dirs, files in os.walk(src):
+ for root, dirs, files in os.walk(src, followlinks=True):
root_parts = root.split(os.sep)
if set(root_parts) & ignore:
continue
@@ -325,12 +630,8 @@ def copy_tree(src, dst, link_cutoff=None):
continue
dst_file = os.path.join(dst_dir, src_name)
src_file = os.path.join(root, src_name)
- if sys.version_info[0] == 2:
- # Python2 prefers encoded str here
- dst_file = sys_encode(dst_file)
- src_file = sys_encode(src_file)
yield {
- 'name': str(dst_file),
+ 'name': dst_file,
'file_dep': [src_file],
'targets': [dst_file],
'actions': [(copy_file, (src_file, dst_file, link_cutoff))],
@@ -397,11 +698,14 @@ def slugify(value):
return _slugify_hyphenate_re.sub('-', value)
-def unslugify(value):
- """
- Given a slug string (as a filename), return a human readable string
+def unslugify(value, discard_numbers=True):
+ """Given a slug string (as a filename), return a human readable string.
+
+ If discard_numbers is True, numbers right at the beginning of input
+ will be removed.
"""
- value = re.sub('^[0-9]+', '', value)
+ if discard_numbers:
+ value = re.sub('^[0-9]+', '', value)
value = re.sub('([_\-\.])', ' ', value)
value = value.strip().capitalize()
return value
@@ -418,55 +722,31 @@ def extract_all(zipfile, path='themes'):
pwd = os.getcwd()
makedirs(path)
os.chdir(path)
- with zip(zipfile) as z:
- namelist = z.namelist()
- for f in namelist:
- if f.endswith('/') and '..' in f:
- raise UnsafeZipException('The zip file contains ".." and is '
- 'not safe to expand.')
- for f in namelist:
- if f.endswith('/'):
- makedirs(f)
- else:
- z.extract(f)
+ z = zipf(zipfile)
+ namelist = z.namelist()
+ for f in namelist:
+ if f.endswith('/') and '..' in f:
+ raise UnsafeZipException('The zip file contains ".." and is '
+ 'not safe to expand.')
+ for f in namelist:
+ if f.endswith('/'):
+ makedirs(f)
+ else:
+ z.extract(f)
+ z.close()
os.chdir(pwd)
-# From https://github.com/lepture/liquidluck/blob/develop/liquidluck/utils.py
def to_datetime(value, tzinfo=None):
- if isinstance(value, datetime.datetime):
- return value
- supported_formats = [
- '%Y/%m/%d %H:%M',
- '%Y/%m/%d %H:%M:%S',
- '%Y/%m/%d %I:%M:%S %p',
- '%a %b %d %H:%M:%S %Y',
- '%Y-%m-%d %H:%M:%S',
- '%Y-%m-%d %H:%M',
- '%Y-%m-%dT%H:%M',
- '%Y%m%d %H:%M:%S',
- '%Y%m%d %H:%M',
- '%Y-%m-%d',
- '%Y%m%d',
- ]
- for format in supported_formats:
- try:
- dt = datetime.datetime.strptime(value, format)
- if tzinfo is None:
- return dt
- # Build a localized time by using a given time zone.
- return tzinfo.localize(dt)
- except ValueError:
- pass
- # So, let's try dateutil
try:
- from dateutil import parser
- dt = parser.parse(value)
- if tzinfo is None or dt.tzinfo:
- return dt
- return tzinfo.localize(dt)
- except ImportError:
- raise ValueError('Unrecognized date/time: {0!r}, try installing dateutil...'.format(value))
+ if not isinstance(value, datetime.datetime):
+ # dateutil does bad things with TZs like UTC-03:00.
+ dateregexp = re.compile(r' UTC([+-][0-9][0-9]:[0-9][0-9])')
+ value = re.sub(dateregexp, r'\1', value)
+ value = dateutil.parser.parse(value)
+ if not value.tzinfo:
+ value = value.replace(tzinfo=tzinfo)
+ return value
except Exception:
raise ValueError('Unrecognized date/time: {0!r}'.format(value))
@@ -474,28 +754,18 @@ def to_datetime(value, tzinfo=None):
def get_tzname(dt):
"""
Given a datetime value, find the name of the time zone.
- """
- try:
- from dateutil import tz
- except ImportError:
- raise ValueError('Unrecognized date/time: {0!r}, try installing dateutil...'.format(dt))
- tzoffset = dt.strftime('%z')
- for name in pytz.common_timezones:
- timezone = tz.gettz(name)
- now = dt.now(timezone)
- offset = now.strftime('%z')
- if offset == tzoffset:
- return name
- raise ValueError('Unrecognized date/time: {0!r}'.format(dt))
+ DEPRECATED: This thing returned basically the 1st random zone
+ that matched the offset.
+ """
+ return dt.tzname()
def current_time(tzinfo=None):
- dt = datetime.datetime.utcnow()
if tzinfo is not None:
- dt = tzinfo.fromutc(dt)
+ dt = datetime.datetime.now(tzinfo)
else:
- dt = pytz.UTC.localize(dt)
+ dt = datetime.datetime.now(dateutil.tz.tzlocal())
return dt
@@ -589,7 +859,7 @@ def get_crumbs(path, is_file=False, index_folder=None):
return list(reversed(_crumbs))
-def get_asset_path(path, themes, files_folders={'files': ''}):
+def get_asset_path(path, themes, files_folders={'files': ''}, _themes_dir='themes'):
"""
.. versionchanged:: 6.1.0
@@ -599,22 +869,22 @@ def get_asset_path(path, themes, files_folders={'files': ''}):
If the asset is not provided by a theme, then it will be checked for
in the FILES_FOLDERS
- >>> print(get_asset_path('assets/css/rst.css', ['bootstrap', 'base'])) # doctest: +SKIP
- [...]/nikola/data/themes/base/assets/css/rst.css
+ >>> print(get_asset_path('assets/css/rst.css', ['bootstrap', 'base']))
+ /.../nikola/data/themes/base/assets/css/rst.css
- >>> print(get_asset_path('assets/css/theme.css', ['bootstrap', 'base'])) # doctest: +SKIP
- [...]/nikola/data/themes/bootstrap/assets/css/theme.css
+ >>> print(get_asset_path('assets/css/theme.css', ['bootstrap', 'base']))
+ /.../nikola/data/themes/bootstrap/assets/css/theme.css
- >>> print(get_asset_path('nikola.py', ['bootstrap', 'base'], {'nikola': ''})) # doctest: +SKIP
- [...]/nikola/nikola.py
+ >>> print(get_asset_path('nikola.py', ['bootstrap', 'base'], {'nikola': ''}))
+ /.../nikola/nikola.py
- >>> print(get_asset_path('nikola/nikola.py', ['bootstrap', 'base'], {'nikola':'nikola'})) # doctest: +SKIP
- [...]/nikola/nikola.py
+ >>> print(get_asset_path('nikola/nikola.py', ['bootstrap', 'base'], {'nikola':'nikola'}))
+ None
"""
for theme_name in themes:
candidate = os.path.join(
- get_theme_path(theme_name),
+ get_theme_path(theme_name, _themes_dir),
path
)
if os.path.isfile(candidate):
@@ -628,6 +898,11 @@ def get_asset_path(path, themes, files_folders={'files': ''}):
return None
+class LocaleBorgUninitializedException(Exception):
+ def __init__(self):
+ super(LocaleBorgUninitializedException, self).__init__("Attempt to use LocaleBorg before initialization")
+
+
class LocaleBorg(object):
"""
Provides locale related services and autoritative current_lang,
@@ -662,6 +937,9 @@ class LocaleBorg(object):
Examples: "Spanish", "French" can't do the full circle set / get / set
That used to break calendar, but now seems is not the case, with month at least
"""
+
+ initialized = False
+
@classmethod
def initialize(cls, locales, initial_lang):
"""
@@ -696,7 +974,7 @@ class LocaleBorg(object):
def __init__(self):
if not self.initialized:
- raise Exception("Attempt to use LocaleBorg before initialization")
+ raise LocaleBorgUninitializedException()
self.__dict__ = self.__shared_state
def set_locale(self, lang):
@@ -734,26 +1012,10 @@ class LocaleBorg(object):
return s
-class ExtendedRSS2(rss.RSS2):
- def publish_extensions(self, handler):
- if self.self_url:
- handler.startElement("atom:link", {
- 'href': self.self_url,
- 'rel': "self",
- 'type': "application/rss+xml"
- })
- handler.endElement("atom:link")
-
-
class ExtendedItem(rss.RSSItem):
def __init__(self, **kw):
- author = kw.pop('author')
- if author and '@' in author[1:]: # Yes, this is a silly way to validate an email
- kw['author'] = author
- self.creator = None
- else:
- self.creator = author
+ self.creator = kw.pop('creator')
# It's an old style class
return rss.RSSItem.__init__(self, **kw)
@@ -824,9 +1086,196 @@ def get_root_dir():
def get_translation_candidate(config, path, lang):
"""
Return a possible path where we can find the translated version of some page
- based on the TRANSLATIONS_PATTERN configuration variable
+ based on the TRANSLATIONS_PATTERN configuration variable.
+
+ >>> config = {'TRANSLATIONS_PATTERN': '{path}.{lang}.{ext}', 'DEFAULT_LANG': 'en', 'TRANSLATIONS': {'es':'1', 'en': 1}}
+ >>> print(get_translation_candidate(config, '*.rst', 'es'))
+ *.es.rst
+ >>> print(get_translation_candidate(config, 'fancy.post.rst', 'es'))
+ fancy.post.es.rst
+ >>> print(get_translation_candidate(config, '*.es.rst', 'es'))
+ *.es.rst
+ >>> print(get_translation_candidate(config, '*.es.rst', 'en'))
+ *.rst
+ >>> print(get_translation_candidate(config, 'cache/posts/fancy.post.es.html', 'en'))
+ cache/posts/fancy.post.html
+ >>> print(get_translation_candidate(config, 'cache/posts/fancy.post.html', 'es'))
+ cache/posts/fancy.post.es.html
+ >>> print(get_translation_candidate(config, 'cache/stories/charts.html', 'es'))
+ cache/stories/charts.es.html
+ >>> print(get_translation_candidate(config, 'cache/stories/charts.html', 'en'))
+ cache/stories/charts.html
+
+ >>> config = {'TRANSLATIONS_PATTERN': '{path}.{ext}.{lang}', 'DEFAULT_LANG': 'en', 'TRANSLATIONS': {'es':'1', 'en': 1}}
+ >>> print(get_translation_candidate(config, '*.rst', 'es'))
+ *.rst.es
+ >>> print(get_translation_candidate(config, '*.rst.es', 'es'))
+ *.rst.es
+ >>> print(get_translation_candidate(config, '*.rst.es', 'en'))
+ *.rst
+ >>> print(get_translation_candidate(config, 'cache/posts/fancy.post.html.es', 'en'))
+ cache/posts/fancy.post.html
+ >>> print(get_translation_candidate(config, 'cache/posts/fancy.post.html', 'es'))
+ cache/posts/fancy.post.html.es
+
"""
+ # FIXME: this is rather slow and this function is called A LOT
+ # Convert the pattern into a regexp
pattern = config['TRANSLATIONS_PATTERN']
- path, ext = os.path.splitext(path)
- ext = ext[1:] if len(ext) > 0 else ext
- return pattern.format(path=path, lang=lang, ext=ext)
+ # This will still break if the user has ?*[]\ in the pattern. But WHY WOULD HE?
+ pattern = pattern.replace('.', r'\.')
+ pattern = pattern.replace('{path}', '(?P<path>.+?)')
+ pattern = pattern.replace('{ext}', '(?P<ext>[^\./]+)')
+ pattern = pattern.replace('{lang}', '(?P<lang>{0})'.format('|'.join(config['TRANSLATIONS'].keys())))
+ m = re.match(pattern, path)
+ if m and all(m.groups()): # It's a translated path
+ p, e, l = m.group('path'), m.group('ext'), m.group('lang')
+ if l == lang: # Nothing to do
+ return path
+ elif lang == config['DEFAULT_LANG']: # Return untranslated path
+ return '{0}.{1}'.format(p, e)
+ else: # Change lang and return
+ return config['TRANSLATIONS_PATTERN'].format(path=p, ext=e, lang=lang)
+ else:
+ # It's a untranslated path, assume it's path.ext
+ p, e = os.path.splitext(path)
+ e = e[1:] # No initial dot
+ if lang == config['DEFAULT_LANG']: # Nothing to do
+ return path
+ else: # Change lang and return
+ return config['TRANSLATIONS_PATTERN'].format(path=p, ext=e, lang=lang)
+
+
+def write_metadata(data):
+ """Write metadata."""
+ order = ('title', 'slug', 'date', 'tags', 'link', 'description', 'type')
+ f = '.. {0}: {1}'
+ meta = []
+ for k in order:
+ try:
+ meta.append(f.format(k, data.pop(k)))
+ except KeyError:
+ pass
+
+ # Leftover metadata (user-specified/non-default).
+ for k, v in data.items():
+ meta.append(f.format(k, v))
+
+ meta.append('')
+
+ return '\n'.join(meta)
+
+
+def ask(query, default=None):
+ """Ask a question."""
+ if default:
+ default_q = ' [{0}]'.format(default)
+ else:
+ default_q = ''
+ inp = raw_input("{query}{default_q}: ".format(query=query, default_q=default_q)).strip()
+ if inp or default is None:
+ return inp
+ else:
+ return default
+
+
+def ask_yesno(query, default=None):
+ """Ask a yes/no question."""
+ if default is None:
+ default_q = ' [y/n]'
+ elif default is True:
+ default_q = ' [Y/n]'
+ elif default is False:
+ default_q = ' [y/N]'
+ inp = raw_input("{query}{default_q} ".format(query=query, default_q=default_q)).strip()
+ if inp:
+ return inp.lower().startswith('y')
+ elif default is not None:
+ return default
+ else:
+ # Loop if no answer and no default.
+ return ask_yesno(query, default)
+
+
+from nikola.plugin_categories import Command
+from doit.cmdparse import CmdParse
+
+
+class CommandWrapper(object):
+ """Converts commands into functions."""
+
+ def __init__(self, cmd, commands_object):
+ self.cmd = cmd
+ self.commands_object = commands_object
+
+ def __call__(self, *args, **kwargs):
+ if args or (not args and not kwargs):
+ self.commands_object._run([self.cmd] + list(args))
+ else:
+ # Here's where the keyword magic would have to go
+ self.commands_object._run_with_kw(self.cmd, *args, **kwargs)
+
+
+class Commands(object):
+
+ """Nikola Commands.
+
+ Sample usage:
+ >>> commands.check('-l') # doctest: +SKIP
+
+ Or, if you know the internal argument names:
+ >>> commands.check(list=True) # doctest: +SKIP
+ """
+
+ def __init__(self, main):
+ """Takes a main instance, works as wrapper for commands."""
+ self._cmdnames = []
+ for k, v in main.get_commands().items():
+ self._cmdnames.append(k)
+ if k in ['run', 'init']:
+ continue
+ if sys.version_info[0] == 2:
+ k2 = bytes(k)
+ else:
+ k2 = k
+ nc = type(
+ k2,
+ (CommandWrapper,),
+ {
+ '__doc__': options2docstring(k, main.sub_cmds[k].options)
+ })
+ setattr(self, k, nc(k, self))
+ self.main = main
+
+ def _run(self, cmd_args):
+ self.main.run(cmd_args)
+
+ def _run_with_kw(self, cmd, *a, **kw):
+ cmd = self.main.sub_cmds[cmd]
+ options, _ = CmdParse(cmd.options).parse([])
+ options.update(kw)
+ if isinstance(cmd, Command):
+ cmd.execute(options=options, args=a)
+ else: # Doit command
+ cmd.execute(options, a)
+
+ def __repr__(self):
+ """Return useful and verbose help."""
+
+ return """\
+<Nikola Commands>
+
+ Sample usage:
+ >>> commands.check('-l')
+
+ Or, if you know the internal argument names:
+ >>> commands.check(list=True)
+
+Available commands: {0}.""".format(', '.join(self._cmdnames))
+
+
+def options2docstring(name, options):
+ result = ['Function wrapper for command %s' % name, 'arguments:']
+ for opt in options:
+ result.append('{0} type {1} default {2}'.format(opt.name, opt.type.__name__, opt.default))
+ return '\n'.join(result)
diff --git a/nikola/winutils.py b/nikola/winutils.py
index 517a326..712de39 100644
--- a/nikola/winutils.py
+++ b/nikola/winutils.py
@@ -26,74 +26,92 @@
"""windows utilities to workaround problems with symlinks in a git clone"""
+from __future__ import print_function, unicode_literals
import os
import shutil
-import sys
-# don't add imports outside stdlib, will be imported in setup.py
+# don't add imports to nikola code, will be imported in setup.py
-def should_fix_git_symlinked():
- """True if git symlinls markers should be filled with the real content"""
- if sys.platform == 'win32':
- path = (os.path.dirname(__file__) +
- r'\data\samplesite\stories\theming.rst')
- try:
- if os.path.getsize(path) < 200:
- return True
- except Exception:
- pass
- return False
+def is_file_into_dir(filename, dirname):
+ try:
+ res = not os.path.relpath(filename, dirname).startswith('.')
+ except ValueError:
+ res = False
+ return res
-def fix_git_symlinked(src, dst):
- """fix git symlinked files in windows that had been copied from src to dst
+def fix_all_git_symlinked(topdir):
+ """inplace conversion of git symlinks to real content
Most (all?) of git implementations in windows store a symlink pointing
into the repo as a text file, the text being the relative path to the
file with the real content.
So, in a clone of nikola in windows the symlinked files will have the
- wrong content.
+ wrong content; a .zip download from Github has the same problem.
- The linux usage pattern for those files is 'copy to some dir, then use',
- so we inspect after the copy and rewrite the wrong contents.
+ This function will rewrite each symlinked file with the correct contents, but
+ keep in mind that the working copy will be seen as dirty by git after operation.
- The goals are:
- support running nikola from a clone without installing and without
- making dirty the WC.
+ Expects to find a list of symlinked files at nikola/data/symlinked.txt
- support install from the WC.
+ The list can be generated by scripts/generate_symlinked_list.sh , which is
+ basically a redirect of
+ cd nikola_checkout
+ git ls-files -s | awk '/120000/{print $4}'
- if possible and needed, support running the test suite without making
- dirty the WC.
+ Weakness: if interrupted of fail amidst a directory copy, next run will not
+ see the missing files.
"""
- # if running from WC there should be a 'doc' dir sibling to nikola package
- if not should_fix_git_symlinked():
- return
- # probabbly in a WC, so symlinks should be fixed
- for root, dirs, files in os.walk(dst):
- for name in files:
- filename = os.path.join(root, name)
-
- # detect if symlinked
- try:
- if not (2 < os.path.getsize(filename) < 500):
- continue
- # which encoding uses a git symlink marker ? betting on default
- with open(filename, 'r') as f:
- text = f.read()
- if text[0] != '.':
- # de facto hint to skip binary files and exclude.meta
- continue
- except Exception:
- # probably encoding: content binary or encoding not defalt,
- # also in py2.6 it can be path encoding
+ with open(topdir + r'\nikola\data\symlinked.txt', 'rb') as f:
+ all_bytes = f.read()
+ text = all_bytes.decode('utf8')
+ # expect each line a relpath from git or zip root,
+ # smoke test relpaths are relative to git root
+ if text.startswith('.'):
+ raise Exception(r'Bad data in \nikola\data\symlinked.txt')
+ relnames = text.split('\n')
+ relnames = [name.strip().replace('/', '\\') for name in relnames]
+ relnames = [name for name in relnames if name]
+
+ failures = 0
+ for name in relnames:
+ # build dst path and do some basic validation
+ dst = os.path.join(topdir, name)
+ # don't access files outside topdir
+ if not is_file_into_dir(dst, topdir):
+ continue
+ if os.path.isdir(dst):
+ # assume the file was de-symlinked
+ continue
+
+ # build src path and do some basic validation
+ with open(os.path.join(topdir, dst), 'r') as f:
+ text = f.read()
+ dst_dir = os.path.dirname(dst)
+ try:
+ src = os.path.normpath(os.path.join(dst_dir, text))
+ if not os.path.exists(src):
+ # assume the file was de-symlinked before
continue
- dst_dir_relpath = os.path.dirname(os.path.relpath(filename, dst))
- path = os.path.normpath(os.path.join(src, dst_dir_relpath, text))
- if not os.path.exists(path):
+ # don't access files outside topdir
+ if not is_file_into_dir(src, topdir):
continue
- # most probably it is a git symlinked file
+ except Exception:
+ # assume the file was de-symlinked before
+ continue
+
+ # copy src to dst
+ try:
+ if os.path.isdir(src):
+ os.unlink(dst)
+ shutil.copytree(src, dst)
+ else:
+ shutil.copy2(src, dst)
+ except Exception:
+ failures += 1
+ print("*** copy failed for")
+ print("\t src:", src)
+ print("\t dst:", dst)
- # copy original content to filename
- shutil.copy(path, filename)
+ return failures
diff --git a/requirements-full.txt b/requirements-extras.txt
index 2743f1b..c393583 100644
--- a/requirements-full.txt
+++ b/requirements-extras.txt
@@ -2,10 +2,8 @@
requests>=1.0
markdown
Jinja2>=2.7
-bbcode
livereload==2.1.0
pyphen
-python-dateutil
micawber
pygal
typogrify>=2.0.4
diff --git a/requirements-tests.txt b/requirements-tests.txt
index fe07dfa..f0bcc3e 100644
--- a/requirements-tests.txt
+++ b/requirements-tests.txt
@@ -1,6 +1,7 @@
--r requirements-full.txt
+-r requirements-extras.txt
mock>=1.0.0
coverage
-nose
+pytest
+pytest-cov
freezegun
python-coveralls
diff --git a/requirements.txt b/requirements.txt
index c4fa50d..b6ead1e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,14 +1,14 @@
doit>=0.23.0
pygments
pillow>=2.0.0
+python-dateutil
docutils
mako>=0.6
unidecode
lxml
yapsy
PyRSS2Gen
-pytz
logbook
blinker
setuptools
-colorama
+natsort>=3.2.0
diff --git a/scripts/generate_symlinked_list.sh b/scripts/generate_symlinked_list.sh
new file mode 100755
index 0000000..fe7a7cc
--- /dev/null
+++ b/scripts/generate_symlinked_list.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# Generate a list of symlinked files and directories.
+# Each line must be the file path, relative to the git root.
+
+WDir="${PWD##*/}"
+[[ $WDir == 'scripts' ]] && cd ..
+
+dst='nikola/data/symlinked.txt'
+git ls-files -s | awk '/120000/{print $4}' > $dst
diff --git a/scripts/getbaseline.sh b/scripts/getbaseline.sh
new file mode 100755
index 0000000..719fbe5
--- /dev/null
+++ b/scripts/getbaseline.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+cd tests/data
+for i in $@; do
+ if [[ $i == '2.7' ]]; then
+ # we only support 2.7 now
+ wget https://github.com/getnikola/invariant-builds/archive/v$i'.zip'
+ unzip 'v'$i'.zip'
+ rm -rf baseline$i
+ mv invariant-builds-$i baseline$i
+ rm 'v'$i'.zip'
+ else
+ echo 'Version '$i' does not support baseline testing.'
+ fi
+done
diff --git a/scripts/getwheelhouse.sh b/scripts/getwheelhouse.sh
new file mode 100755
index 0000000..911ffbd
--- /dev/null
+++ b/scripts/getwheelhouse.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+for i in $@; do
+ wget https://github.com/getnikola/wheelhouse/archive/v$i'.zip'
+ unzip 'v'$i'.zip'
+ pip install --use-wheel --no-index --find-links=wheelhouse-$i lxml Pillow ipython
+ rm -rf wheelhouse-$i 'v'$i'.zip'
+done
diff --git a/scripts/import_po.py b/scripts/import_po.py
index 7e99064..50afab9 100755
--- a/scripts/import_po.py
+++ b/scripts/import_po.py
@@ -25,22 +25,6 @@ MESSAGES = {""".splitlines()
lines2 = []
for entry in po:
lines2.append(' "{0}": "{1}",'. format(entry.msgid, entry.msgstr))
- ### BACKWARDS COMPATIBILITY PATCH START
- ### TODO: remove in v7
- if entry.msgid in ["Posted:", "Also available in:"]:
- fid = entry.msgid
- fid = fid.replace(':', '')
- fstr = entry.msgstr
- fstr = fstr.replace(':', '').replace(':', '')
- lines2.append(' "{0}": "{1}",'. format(fid, fstr))
- elif entry.msgid == 'More posts about %s':
- fid = entry.msgid
- fid = fid.replace(' %s', '')
- fstr = entry.msgstr
- fstr = fstr.replace(' %s', '').replace('%s', '')
- lines2.append(' "{0}": "{1}",'. format(fid, fstr))
- ### BACKWARDS COMPATIBILITY PATCH END
- ### TODO: remove in v7
lines.extend(sorted(lines2))
lines.append("}\n")
print("Generating:", outf)
diff --git a/scripts/jinjify.py b/scripts/jinjify.py
new file mode 100755
index 0000000..5f07032
--- /dev/null
+++ b/scripts/jinjify.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python
+import codecs
+import glob
+import sys
+import os
+import re
+import json
+import shutil
+
+import colorama
+import jinja2
+
+dumb_replacements = [
+ ["{% if isinstance(url, tuple) %}", "{% if url is mapping %}"],
+ ["{% if any(post.is_mathjax for post in posts) %}", '{% if posts|selectattr("is_mathjax")|list %}'],
+ ["json.dumps(title)", "title|tojson"],
+ ["{{ parent.extra_head() }}", "{{ super() }}"],
+ ["prefix='\\", "prefix='"],
+ ["og: http://ogp.me/ns# \\", "og: http://ogp.me/ns#"],
+ ["article: http://ogp.me/ns/article# \\", "article: http://ogp.me/ns/article#"],
+ ["fb: http://ogp.me/ns/fb# \\", "fb: http://ogp.me/ns/fb#"],
+ ['dir="rtl" \\', 'dir="rtl"']
+]
+
+dumber_replacements = [
+ ["<html\n\\", "<html\n"],
+ ["\n'\\\n", "\n'\n"],
+ ["{% endif %}\n\\", "{% endif %}\n"]
+]
+
+
+def jinjify(in_theme, out_theme):
+ """Convert in_theme into a jinja version and put it in out_theme"""
+
+ in_templates_path = os.path.join(in_theme, "templates")
+ out_templates_path = os.path.join(out_theme, "templates")
+ try:
+ os.makedirs(out_templates_path)
+ except:
+ pass
+ lookup = jinja2.Environment()
+ lookup.filters['tojson'] = json.dumps
+ lookup.loader = jinja2.FileSystemLoader([out_templates_path], encoding='utf-8')
+ for template in glob.glob(os.path.join(in_templates_path, "*.tmpl")):
+ out_template = os.path.join(out_templates_path, os.path.basename(template))
+ with codecs.open(template, "r", "utf-8") as inf:
+ data = mako2jinja(inf)
+
+ lines = []
+ for line in data.splitlines():
+ for repl in dumb_replacements:
+ line = line.replace(*repl)
+ lines.append(line)
+ data = '\n'.join(lines)
+
+ for repl in dumber_replacements:
+ data = data.replace(*repl)
+
+ with codecs.open(out_template, "wb+", "utf-8") as outf:
+ outf.write(data + '\n')
+
+ # Syntax check output
+ source, filename = lookup.loader.get_source(lookup, os.path.basename(template))[:2]
+ try:
+ lookup.parse(source)
+ except Exception as e:
+ error("Syntax error in {0}:{1}".format(out_template, e.lineno))
+
+ parent = os.path.basename(in_theme.rstrip('/'))
+ child = os.path.basename(out_theme.rstrip('/'))
+ mappings = {
+ 'base-jinja': 'base',
+ 'bootstrap-jinja': 'base-jinja',
+ 'bootstrap3-jinja': 'bootstrap-jinja',
+ }
+
+ if child in mappings:
+ parent = mappings[child]
+
+ with open(os.path.join(out_theme, "parent"), "wb+") as outf:
+ outf.write(parent + '\n')
+
+ with open(os.path.join(out_theme, "engine"), "wb+") as outf:
+ outf.write("jinja\n")
+
+ # Copy assets
+ # shutil.rmtree(os.path.join(out_theme, "assets"))
+ # shutil.copytree(os.path.join(in_theme, "assets"), os.path.join(out_theme, "assets"))
+
+ # Copy bundles
+ # shutil.copy(os.path.join(in_theme, "bundles"), os.path.join(out_theme, "bundles"))
+
+ # Copy README
+ if os.path.isfile(os.path.join(in_theme, "README.md")):
+ shutil.copy(os.path.join(in_theme, "README.md"), os.path.join(out_theme, "README.md"))
+
+
+def error(msg):
+ print(colorama.Fore.RED + "ERROR:" + msg)
+
+
+def mako2jinja(input_file):
+
+ output = ''
+
+ # TODO: OMG, this code is so horrible. Look at it; just look at it:
+
+ macro_start = re.compile(r'(.*)<%.*def name="(.*?)".*>(.*)', re.IGNORECASE)
+ macro_end = re.compile(r'(.*)</%def>(.*)', re.IGNORECASE)
+
+ if_start = re.compile(r'(.*)% *if (.*):(.*)', re.IGNORECASE)
+ if_else = re.compile(r'(.*)% *else.*:(.*)', re.IGNORECASE)
+ if_elif = re.compile(r'(.*)% *elif (.*):(.*)', re.IGNORECASE)
+ if_end = re.compile(r'(.*)% *endif(.*)', re.IGNORECASE)
+
+ for_start = re.compile(r'(.*)% *for (.*):(.*)', re.IGNORECASE)
+ for_end = re.compile(r'(.*)% *endfor(.*)', re.IGNORECASE)
+
+ namespace = re.compile(r'(.*)<% *namespace name="(.*?)".* file="(.*?)".*/>(.*)', re.IGNORECASE)
+ inherit = re.compile(r'(.*)<% *inherit file="(.*?)".*/>(.*)', re.IGNORECASE)
+
+ block_single_line = re.compile(r'(.*)<% *block.*name="(.*?)".*>(.*)</% *block>(.*)', re.IGNORECASE)
+ block_start = re.compile(r'(.*)<% *block.*name="(.*?)".*>(.*)', re.IGNORECASE)
+ block_end = re.compile(r'(.*)</%block>(.*)', re.IGNORECASE)
+
+ val = re.compile(r'\$\{(.*?)\}', re.IGNORECASE)
+ func_len = re.compile(r'len\((.*?)\)', re.IGNORECASE)
+ filter_h = re.compile(r'\|h', re.IGNORECASE)
+ filter_striphtml = re.compile(r'\|striphtml', re.IGNORECASE)
+ filter_u = re.compile(r'\|u', re.IGNORECASE)
+
+ comment_single_line = re.compile(r'^.*##(.*?)$', re.IGNORECASE)
+
+ for line in input_file:
+
+ # Process line for repeated inline replacements
+ m_val = val.search(line)
+ m_func_len = func_len.search(line)
+ m_filter_h = filter_h.search(line)
+ m_filter_striphtml = filter_striphtml.search(line)
+ m_filter_u = filter_u.search(line)
+
+ if m_val:
+ line = val.sub(r'{{ \1 }}', line)
+
+ if m_filter_h:
+ line = filter_h.sub(r'|e', line)
+
+ if m_filter_striphtml:
+ line = filter_striphtml.sub(r'|e', line)
+
+ if m_filter_u:
+ line = filter_u.sub(r'|urlencode', line)
+
+ if m_func_len:
+ line = func_len.sub(r'\1|length', line)
+
+ # Process line for single 'whole line' replacements
+ m_macro_start = macro_start.search(line)
+ m_macro_end = macro_end.search(line)
+ m_if_start = if_start.search(line)
+ m_if_else = if_else.search(line)
+ m_if_elif = if_elif.search(line)
+ m_if_end = if_end.search(line)
+ m_for_start = for_start.search(line)
+ m_for_end = for_end.search(line)
+ m_namspace = namespace.search(line)
+ m_inherit = inherit.search(line)
+ m_block_single_line = block_single_line.search(line)
+ m_block_start = block_start.search(line)
+ m_block_end = block_end.search(line)
+
+ m_comment_single_line = comment_single_line.search(line)
+
+ if m_comment_single_line:
+ output += m_comment_single_line.expand(r'{# \1 #}') + '\n'
+
+ elif m_macro_start:
+ output += m_macro_start.expand(r'\1{% macro \2 %}\3') + '\n'
+ elif m_macro_end:
+ output += m_macro_end.expand(r'\1{% endmacro %}\1') + '\n'
+
+ elif m_if_start:
+ output += m_if_start.expand(r'\1{% if \2 %}\3') + '\n'
+ elif m_if_else:
+ output += m_if_else.expand(r'\1{% else %}\2') + '\n'
+ elif m_if_elif:
+ output += m_if_elif.expand(r'\1{% elif \2 %}\3') + '\n'
+ elif m_if_end:
+ output += m_if_end.expand(r'\1{% endif %}\2') + '\n'
+
+ elif m_for_start:
+ output += m_for_start.expand(r'\1{% for \2 %}\3') + '\n'
+ elif m_for_end:
+ output += m_for_end.expand(r'\1{% endfor %}\2') + '\n'
+
+ elif m_namspace:
+ output += m_namspace.expand(r"\1{% import '\3' as \2 with context %}\4") + '\n'
+ elif m_inherit:
+ output += m_inherit.expand(r"{% extends '\2' %}\3") + '\n'
+
+ elif m_block_single_line:
+ output += m_block_single_line.expand(r'\1{% block \2 %}\3{% endblock %}\4') + '\n'
+ elif m_block_start:
+ output += m_block_start.expand(r'\1{% block \2 %}\3') + '\n'
+ elif m_block_end:
+ output += m_block_end.expand(r'\1{% endblock %}\2') + '\n'
+
+ else:
+ # Doesn't match anything we're going to process, pass though
+ output += line
+
+ return output
+
+if __name__ == "__main__":
+ if len(sys.argv) != 3:
+ print('ERROR: needs exactly two arguments, input and output directory.')
+ else:
+ jinjify(sys.argv[1], sys.argv[2])
diff --git a/scripts/nikola b/scripts/nikola
deleted file mode 100755
index 16ac701..0000000
--- a/scripts/nikola
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env python
-
-"""Nikola main script."""
-
-from __future__ import print_function
-import os
-import sys
-
-# LIBDIR trick start (marker for removal on platforms that don't need it)
-libdir = '@LIBDIR@'
-
-# Two cases:
-if libdir != '@' 'LIBDIR' '@':
- # Changed by our distutils hook, then use the given path.
-
- if not os.path.isabs(libdir):
- libdir = os.path.join(os.path.dirname(
- os.path.realpath(__file__)), libdir)
- libdir = os.path.abspath(libdir)
-else:
- # Unchanged, running from checkout,
- # use the parent directory, the nikola package ought be there.
- libdir = os.path.join(os.path.dirname(__file__), "..")
-
-sys.path.insert(0, libdir)
-
-if "PYTHONPATH" not in os.environ:
- os.environ["PYTHONPATH"] = libdir
-else:
- os.environ["PYTHONPATH"] = os.environ["PYTHONPATH"] + ":" + libdir
-
-# LIBDIR trick end (marker for removal on platforms that don't need it)
-
-from nikola import __main__
-
-if __name__ == "__main__":
- sys.exit(__main__.main(sys.argv[1:]))
diff --git a/scripts/nikola.bat b/scripts/nikola.bat
deleted file mode 100755
index 0aad2d4..0000000
--- a/scripts/nikola.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-python "%~dpn0" %* \ No newline at end of file
diff --git a/scripts/set_version.py b/scripts/set_version.py
index 38ea03c..100a9f7 100755
--- a/scripts/set_version.py
+++ b/scripts/set_version.py
@@ -23,9 +23,8 @@ def sed_like_thing(pattern, repl, path):
outf.write(data)
if __name__ == "__main__":
- print("New version number (in format X.Y.Z): ", end="")
- sys.stdout.flush()
- version = sys.stdin.readline().strip()
+ inpf = raw_input if sys.version_info[0] == 2 else input
+ version = inpf("New version number (in format X.Y.Z): ").strip()
for doc in glob.glob(os.path.join("docs/*.txt")):
sed_like_thing(":Version: .*", ":Version: {0}".format(version), doc)
diff --git a/scripts/theme_snapshot b/scripts/theme_snapshot
index ab3ac7f..391f9c6 100755
--- a/scripts/theme_snapshot
+++ b/scripts/theme_snapshot
@@ -7,7 +7,7 @@
theme_name=$1
tempsite=temp_$theme_name
-nikola init $tempsite
+nikola init -q $tempsite
cd $tempsite
doit install_theme -n $theme_name
sed -i s/\'site\'/\'$theme_name\'/g conf.py
diff --git a/setup.cfg b/setup.cfg
index 5995929..d672d70 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
[wheel]
-universal = 1
+universal = 0
[flake8]
ignore=E501
diff --git a/setup.py b/setup.py
index 9afda23..815b01d 100755
--- a/setup.py
+++ b/setup.py
@@ -12,22 +12,38 @@ import os
import subprocess
import sys
import shutil
-
from setuptools import setup
from setuptools.command.install import install
+from setuptools.command.test import test as TestCommand
+
+
+class PyTest(TestCommand):
+ def finalize_options(self):
+ TestCommand.finalize_options(self)
+ self.test_args = []
+ self.test_suite = True
+
+ def run_tests(self):
+ # import here, cause outside the eggs aren't loaded
+ import pytest
+ errno = pytest.main(self.test_args)
+ sys.exit(errno)
+
with open('requirements.txt', 'r') as fh:
dependencies = [l.strip() for l in fh]
-########### platform specific stuff #############
-import platform
-platform_system = platform.system()
+extras = {}
+
+with open('requirements-extras.txt', 'r') as fh:
+ extras['extras'] = [l.strip() for l in fh][1:]
+ # Alternative name.
+ extras['full'] = extras['extras']
-scripts = ['scripts/nikola']
-# platform specific scripts
-if platform_system == "Windows":
- scripts.append('scripts/nikola.bat')
+with open('requirements-tests.txt', 'r') as fh:
+ extras['tests'] = [l.strip() for l in fh][1:]
+# ########## platform specific stuff #############
if sys.version_info[0] == 2 and sys.version_info[1] < 6:
raise Exception('Python 2 version < 2.6 is not supported')
elif sys.version_info[0] == 3 and sys.version_info[1] < 3:
@@ -35,10 +51,6 @@ elif sys.version_info[0] == 3 and sys.version_info[1] < 3:
##################################################
-if sys.version_info[0] == 2:
- # in Python 3 this becomes a builtin, for Python 2 we need the backport
- dependencies.append('configparser')
-
# Provided as an attribute, so you can append to these instead
# of replicating them:
standard_exclude = ('*.pyc', '*$py.class', '*~', '.*', '*.bak')
@@ -62,42 +74,31 @@ def copy_messages():
shutil.copytree(original_messages_directory, theme_messages_directory)
-def copy_symlinked_for_windows():
+def expands_symlinks_for_windows():
"""replaces the symlinked files with a copy of the original content.
In windows (msysgit), a symlink is converted to a text file with a
path to the file it points to. If not corrected, installing from a git
clone will end with some files with bad content
- After install the WC will be dirty (symlink markers rewroted with real
- content)
+ After install the working copy will be dirty (symlink markers rewroted with
+ real content)
"""
-
- # essentially nikola.utils.should_fix_git_symlinked inlined, to not
- # fiddle with sys.path / import unless really needed
if sys.platform != 'win32':
return
- path = (os.path.dirname(__file__) +
- r'nikola\data\samplesite\stories\theming.rst')
- try:
- if os.path.getsize(path) < 200:
- pass
- else:
- return
- except Exception:
- return
# apply the fix
- localdir = os.path.dirname(__file__)
- dst = os.path.join(localdir, 'nikola', 'data', 'samplesite')
- src = dst
+ localdir = os.path.dirname(os.path.abspath(__file__))
oldpath = sys.path[:]
sys.path.insert(0, os.path.join(localdir, 'nikola'))
winutils = __import__('winutils')
- winutils.fix_git_symlinked(src, dst)
+ failures = winutils.fix_all_git_symlinked(localdir)
sys.path = oldpath
del sys.modules['winutils']
- print('WARNING: your working copy is now dirty by changes in samplesite')
+ print('WARNING: your working copy is now dirty by changes in samplesite, sphinx and themes')
+ if failures:
+ raise Exception("Error: \n\tnot all symlinked files could be fixed." +
+ "\n\tYour best bet is to start again from clean.")
def install_manpages(root, prefix):
@@ -127,15 +128,30 @@ def install_manpages(root, prefix):
print("Not installing the man pages:", e)
+def remove_old_files(self):
+ tree = os.path.join(self.install_lib, 'nikola')
+ tree2 = os.path.join('build', 'lib', 'nikola')
+ try:
+ shutil.rmtree(tree, ignore_errors=True)
+ except:
+ pass
+
+ try:
+ shutil.rmtree(tree2, ignore_errors=True)
+ except:
+ pass
+
+
class nikola_install(install):
def run(self):
- copy_symlinked_for_windows()
+ expands_symlinks_for_windows()
+ remove_old_files(self)
install.run(self)
install_manpages(self.root, self.prefix)
setup(name='Nikola',
- version='6.4.0',
+ version='7.0.1',
description='A modular, fast, simple, static website generator',
long_description=open('README.rst').read(),
author='Roberto Alsina and others',
@@ -144,45 +160,49 @@ setup(name='Nikola',
packages=['nikola',
'nikola.plugins',
'nikola.plugins.command',
- 'nikola.plugins.command.planetoid',
'nikola.plugins.compile',
'nikola.plugins.compile.ipynb',
'nikola.plugins.compile.markdown',
'nikola.plugins.compile.rest',
'nikola.plugins.task',
- 'nikola.plugins.task.localsearch',
- 'nikola.plugins.task.mustache',
'nikola.plugins.task.sitemap',
'nikola.plugins.template',
],
license='MIT',
keywords='website, static',
- scripts=scripts,
- classifiers=('Development Status :: 5 - Production/Stable',
- 'Environment :: Console',
- 'Environment :: Plugins',
- 'Environment :: Web Environment',
- 'Intended Audience :: End Users/Desktop',
- 'License :: OSI Approved :: MIT License',
- 'Operating System :: MacOS',
- 'Operating System :: Microsoft :: Windows',
- 'Operating System :: OS Independent',
- 'Operating System :: POSIX',
- 'Operating System :: Unix',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2.6',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3.3',
- 'Topic :: Internet',
- 'Topic :: Internet :: WWW/HTTP',
- 'Topic :: Text Processing :: Markup'),
+ classifiers=(b'Development Status :: 5 - Production/Stable',
+ b'Environment :: Console',
+ b'Environment :: Plugins',
+ b'Environment :: Web Environment',
+ b'Intended Audience :: End Users/Desktop',
+ b'License :: OSI Approved :: MIT License',
+ b'Operating System :: MacOS',
+ b'Operating System :: Microsoft :: Windows',
+ b'Operating System :: OS Independent',
+ b'Operating System :: POSIX',
+ b'Operating System :: Unix',
+ b'Programming Language :: Python',
+ b'Programming Language :: Python :: 2.6',
+ b'Programming Language :: Python :: 2.7',
+ b'Programming Language :: Python :: 3.3',
+ b'Programming Language :: Python :: 3.4',
+ b'Topic :: Internet',
+ b'Topic :: Internet :: WWW/HTTP',
+ b'Topic :: Text Processing :: Markup'),
install_requires=dependencies,
+ extras_require=extras,
+ tests_require=['pytest'],
include_package_data=True,
- cmdclass={'install': nikola_install},
+ cmdclass={'install': nikola_install, 'test': PyTest},
data_files=[
('share/doc/nikola', [
'docs/manual.txt',
'docs/theming.txt',
'docs/extending.txt']),
],
+ entry_points = {
+ 'console_scripts': [
+ 'nikola = nikola.__main__:main'
+ ]
+ },
)
diff --git a/tests/README.rst b/tests/README.rst
index 8b2199a..cdf5c8a 100644
--- a/tests/README.rst
+++ b/tests/README.rst
@@ -70,10 +70,9 @@ How to execute the tests
The command to execute tests is::
- nosetests --with-coverage --cover-package=nikola --with-doctest --doctest-options=+NORMALIZE_WHITESPACE --logging-filter=-yapsy
+ doit coverage
-However, this command may change at any given moment. Check the
-``/.travis.yml`` file to get the current command.
+Note that Travis does not use this command — and as such, differences between the two may appear.
In Windows you want to drop the doctests parts, they fail over trivial differences in OS details.
diff --git a/tests/__init__.py b/tests/__init__.py
index 6ad8bac..e69de29 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,25 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright © 2012-2014 Roberto Alsina and others.
-
-# Permission is hereby granted, free of charge, to any
-# person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the
-# Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice
-# shall be included in all copies or substantial portions of
-# the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/tests/base.py b/tests/base.py
index f3e3545..c22fbb2 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -22,11 +22,21 @@ import unittest
import logbook
-# Make logbook shutup
import nikola.utils
-
nikola.utils.LOGGER.handlers.append(logbook.TestHandler())
+from yapsy.PluginManager import PluginManager
+from nikola.plugin_categories import (
+ Command,
+ Task,
+ LateTask,
+ TemplateSystem,
+ PageCompiler,
+ TaskMultiplier,
+ RestExtension,
+ MarkdownExtension
+)
+
if sys.version_info < (2, 7):
@@ -167,3 +177,68 @@ class LocaleSupportInTesting(object):
raise ValueError('Unknown locale variant')
nikola.utils.LocaleBorg.reset()
nikola.utils.LocaleBorg.initialize(locales, default_lang)
+
+
+class FakePost(object):
+
+ def __init__(self, title, slug):
+ self._title = title
+ self._slug = slug
+ self._meta = {'slug': slug}
+
+ def title(self):
+ return self._title
+
+ def meta(self, key):
+ return self._meta[key]
+
+ def permalink(self):
+ return '/posts/' + self._slug
+
+
+class FakeSite(object):
+ def __init__(self):
+ self.template_system = self
+ self.invariant = False
+ self.config = {
+ 'DISABLED_PLUGINS': [],
+ 'EXTRA_PLUGINS': [],
+ 'DEFAULT_LANG': 'en',
+ 'MARKDOWN_EXTENSIONS': ['fenced_code', 'codehilite'],
+ 'TRANSLATIONS_PATTERN': '{path}.{lang}.{ext}',
+ }
+ self.EXTRA_PLUGINS = self.config['EXTRA_PLUGINS']
+ self.plugin_manager = PluginManager(categories_filter={
+ "Command": Command,
+ "Task": Task,
+ "LateTask": LateTask,
+ "TemplateSystem": TemplateSystem,
+ "PageCompiler": PageCompiler,
+ "TaskMultiplier": TaskMultiplier,
+ "RestExtension": RestExtension,
+ "MarkdownExtension": MarkdownExtension,
+ })
+ self.loghandlers = [nikola.utils.STDERR_HANDLER]
+ self.plugin_manager.setPluginInfoExtension('plugin')
+ if sys.version_info[0] == 3:
+ places = [
+ os.path.join(os.path.dirname(nikola.utils.__file__), 'plugins'),
+ ]
+ else:
+ places = [
+ os.path.join(os.path.dirname(nikola.utils.__file__), nikola.utils.sys_encode('plugins')),
+ ]
+ self.plugin_manager.setPluginPlaces(places)
+ self.plugin_manager.collectPlugins()
+
+ self.timeline = [
+ FakePost(title='Fake post',
+ slug='fake-post')
+ ]
+ self.debug = True
+ # This is to make plugin initialization happy
+ self.template_system = self
+ self.name = 'mako'
+
+ def render_template(self, name, _, context):
+ return('<img src="IMG.jpg">')
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..fbb09c8
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,8 @@
+import os
+import pytest
+
+@pytest.yield_fixture(autouse=True)
+def ensure_chdir():
+ x = os.getcwd()
+ yield
+ os.chdir(x)
diff --git a/tests/data/translated_titles/conf.py b/tests/data/translated_titles/conf.py
index edfce3e..4904586 100644
--- a/tests/data/translated_titles/conf.py
+++ b/tests/data/translated_titles/conf.py
@@ -1,40 +1,68 @@
# -*- coding: utf-8 -*-
+
from __future__ import unicode_literals
import time
-##############################################
-# Configuration, please edit
-##############################################
+# !! This is the configuration of Nikola. !!#
+# !! You should edit it to your liking. !!#
+
+
+# ! Some settings can be different in different languages.
+# ! A comment stating (translatable) is used to denote those.
+# ! There are two ways to specify a translatable setting:
+# ! (a) BLOG_TITLE = "My Blog"
+# ! (b) BLOG_TITLE = {"en": "My Blog", "es": "Mi Blog"}
+# ! Option (a) is there for backwards compatibility and when you don't
+# ! want that setting translated.
+# ! Option (b) should be used for settings that are different in
+# ! different languages.
# Data about this site
-BLOG_AUTHOR = "Your Name"
-BLOG_TITLE = "Demo Site"
+BLOG_AUTHOR = "Your Name" # (translatable)
+BLOG_TITLE = "Demo Site" # (translatable)
# This is the main URL for your site. It will be used
# in a prominent link
-SITE_URL = "http://nikola.ralsina.com.ar"
+SITE_URL = "http://getnikola.com/"
# This is the URL where nikola's output will be deployed.
# If not set, defaults to SITE_URL
-# BASE_URL = "http://nikola.ralsina.com.ar
+# BASE_URL = "http://getnikola.com/"
BLOG_EMAIL = "joe@demo.site"
-BLOG_DESCRIPTION = "This is a demo site for Nikola."
+BLOG_DESCRIPTION = "This is a demo site for Nikola." # (translatable)
# Nikola is multilingual!
#
# Currently supported languages are:
-# English -> en
-# Greek -> gr
-# German -> de
-# French -> fr
-# Polish -> pl
-# Russian -> ru
-# Spanish -> es
-# Italian -> it
-# Simplified Chinese -> zh-cn
+# bg Bulgarian
+# ca Catalan
+# cs Czech [ALTERNATIVELY cz]
+# de German
+# el Greek [NOT gr!]
+# en English
+# eo Esperanto
+# es Spanish
+# et Estonian
+# eu Basque
+# fa Persian
+# fi Finnish
+# fr French
+# hi Hindi
+# hr Croatian
+# it Italian
+# ja Japanese [NOT jp!]
+# nb Norwegian Bokmål
+# nl Dutch
+# pt_br Portuguese (Brasil)
+# pl Polish
+# ru Russian
+# sl Slovenian [NOT sl_si!]
+# tr Turkish (Turkey) [NOT tr_tr!]
+# ur Urdu
+# zh_cn Chinese (Simplified)
#
# If you want to use Nikola with a non-supported language you have to provide
# a module containing the necessary translations
-# (p.e. look at the modules at: ./nikola/data/themes/default/messages/fr.py).
+# (cf. the modules at nikola/data/themes/base/messages/).
# If a specific post is not translated to a language, then the version
# in the default language will be shown instead.
@@ -46,47 +74,53 @@ DEFAULT_LANG = "en"
# the path will be used as a prefix for the generated pages location
TRANSLATIONS = {
"en": "",
- # Example for another language:
"pl": "./pl",
}
# What will translated input files be named like?
-# If you have a page something.rst, then something.rst.pl will be considered
+# If you have a page something.rst, then something.pl.rst will be considered
# its Polish translation.
-# (in the above example: path == "something", lang == "pl", ext == "rst")
+# (in the above example: path == "something", ext == "rst", lang == "pl")
# this pattern is also used for metadata:
-# something.meta -> something.meta.pl
+# something.meta -> something.pl.meta
-TRANSLATIONS_PATTERN = "{path}.{ext}.{lang}"
-
-# If you don't want your Polish files to be considered Perl code, use this:
-# TRANSLATIONS_PATTERN = "{path}.{lang}.{ext}"
-# Note that this pattern will become the default in v7.0.0.
+TRANSLATIONS_PATTERN = "{path}.{lang}.{ext}"
# Links for the sidebar / navigation bar.
# You should provide a key-value pair for each used language.
-SIDEBAR_LINKS = {
+# (the same way you would do with a (translatable) setting.)
+NAVIGATION_LINKS = {
DEFAULT_LANG: (
('/archive.html', 'Archives'),
('/categories/index.html', 'Tags'),
+ ('/rss.xml', 'RSS'),
),
- "pl": ()
}
-
-##############################################
# Below this point, everything is optional
-##############################################
-
-# post_pages contains (wildcard, destination, template, use_in_feed) tuples.
+# While nikola can select a sensible locale for each language,
+# sometimes explicit control can come handy.
+# In this file we express locales in the string form that
+# python's locales will accept in your OS, by example
+# "en_US.utf8" in unix-like OS, "English_United States" in Windows.
+# LOCALES = dict mapping language --> explicit locale for the languages
+# in TRANSLATIONS. You can ommit one or more keys.
+# LOCALE_FALLBACK = locale to use when an explicit locale is unavailable
+# LOCALE_DEFAULT = locale to use for languages not mentioned in LOCALES; if
+# not set the default Nikola mapping is used.
+
+# POSTS and PAGES contains (wildcard, destination, template) tuples.
#
# The wildcard is used to generate a list of reSt source files
# (whatever/thing.txt).
-# That fragment must have an associated metadata file (whatever/thing.meta),
+#
+# That fragment could have an associated metadata file (whatever/thing.meta),
# and optionally translated files (example for spanish, with code "es"):
-# whatever/thing.txt.es and whatever/thing.meta.es
+# whatever/thing.es.txt and whatever/thing.es.meta
+#
+# This assumes you use the default TRANSLATIONS_PATTERN.
#
# From those files, a set of HTML fragment files will be generated:
# cache/whatever/thing.html (and maybe cache/whatever/thing.html.es)
@@ -95,15 +129,20 @@ SIDEBAR_LINKS = {
# pages, which will be placed at
# output / TRANSLATIONS[lang] / destination / pagename.html
#
-# where "pagename" is specified in the metadata file.
+# where "pagename" is the "slug" specified in the metadata file.
#
-# if use_in_feed is True, then those posts will be added to the site's
-# rss feeds.
+# The difference between POSTS and PAGES is that POSTS are added
+# to feeds and are considered part of a blog, while PAGES are
+# just independent HTML pages.
#
-post_pages = (
- ("posts/*.txt", "posts", "post.tmpl", True),
- ("stories/*.txt", "stories", "story.tmpl", False),
+POSTS = (
+ ("posts/*.rst", "posts", "post.tmpl"),
+ ("posts/*.txt", "posts", "post.tmpl"),
+)
+PAGES = (
+ ("stories/*.rst", "stories", "story.tmpl"),
+ ("stories/*.txt", "stories", "story.tmpl"),
)
# One or more folders containing files to be copied as-is into the output.
@@ -120,20 +159,35 @@ post_pages = (
# 'markdown' is MarkDown
# 'html' assumes the file is html and just copies it
COMPILERS = {
- "rest": ('.txt', '.rst'),
+ "rest": ('.rst', '.txt'),
"markdown": ('.md', '.mdown', '.markdown'),
"textile": ('.textile',),
"txt2tags": ('.t2t',),
"bbcode": ('.bb',),
"wiki": ('.wiki',),
"ipynb": ('.ipynb',),
- "html": ('.html', '.htm')
+ "html": ('.html', '.htm'),
+ # PHP files are rendered the usual way (i.e. with the full templates).
+ # The resulting files have .php extensions, making it possible to run
+ # them without reconfiguring your server to recognize them.
+ "php": ('.php',),
+ # Pandoc detects the input from the source filename
+ # but is disabled by default as it would conflict
+ # with many of the others.
+ # "pandoc": ('.rst', '.md', '.txt'),
}
# Create by default posts in one file format?
# Set to False for two-file posts, with separate metadata.
# ONE_FILE_POSTS = True
+# If this is set to True, the DEFAULT_LANG version will be displayed for
+# untranslated posts.
+# If this is set to False, then posts that are not translated to a language
+# LANG will not be visible at all in the pages in that language.
+# Formerly known as HIDE_UNTRANSLATED_POSTS (inverse)
+# SHOW_UNTRANSLATED_POSTS = True
+
# Paths for different autogenerated bits. These are combined with the
# translation paths.
@@ -147,17 +201,34 @@ COMPILERS = {
# the posts themselves. If set to False, it will be just a list of links.
# TAG_PAGES_ARE_INDEXES = True
-# Final location is output / TRANSLATION[lang] / INDEX_PATH / index-*.html
+# Final location for the main blog page and sibling paginated pages is
+# output / TRANSLATION[lang] / INDEX_PATH / index-*.html
# INDEX_PATH = ""
+
+# Create per-month archives instead of per-year
+# CREATE_MONTHLY_ARCHIVE = False
+# Create one large archive instead of per-year
+# CREATE_SINGLE_ARCHIVE = False
# Final locations for the archives are:
# output / TRANSLATION[lang] / ARCHIVE_PATH / ARCHIVE_FILENAME
# output / TRANSLATION[lang] / ARCHIVE_PATH / YEAR / index.html
+# output / TRANSLATION[lang] / ARCHIVE_PATH / YEAR / MONTH / index.html
# ARCHIVE_PATH = ""
# ARCHIVE_FILENAME = "archive.html"
-# Final locations are:
+
+# URLs to other posts/pages can take 3 forms:
+# rel_path: a relative URL to the current page/post (default)
+# full_path: a URL with the full path from the root
+# absolute: a complete URL (that includes the SITE_URL)
+# URL_TYPE = 'rel_path'
+
+# Final location for the blog main RSS feed is:
# output / TRANSLATION[lang] / RSS_PATH / rss.xml
# RSS_PATH = ""
+# Number of posts in RSS feeds
+# FEED_LENGTH = 10
+
# Slug the Tag URL easier for users to type, special characters are
# often removed or replaced as well.
# SLUG_TAG_PATH = True
@@ -169,12 +240,13 @@ COMPILERS = {
# relative URL.
#
# If you don't need any of these, just set to []
-# REDIRECTIONS = []
+REDIRECTIONS = []
# Commands to execute to deploy. Can be anything, for example,
# you may use rsync:
-# "rsync -rav output/* joe@my.site:/srv/www/site"
-# And then do a backup, or ping pingomatic.
+# "rsync -rav --delete output/ joe@my.site:/srv/www/site"
+# And then do a backup, or run `nikola ping` from the `ping`
+# plugin (`nikola install_plugin ping`).
# To do manual deployment, set it to []
# DEPLOY_COMMANDS = []
@@ -205,14 +277,39 @@ COMPILERS = {
# argument.
#
# By default, there are no filters.
+#
+# Many filters are shipped with Nikola. A list is available in the manual:
+# <http://getnikola.com/handbook.html#post-processing-filters>
# FILTERS = {
# ".jpg": ["jpegoptim --strip-all -m75 -v %s"],
# }
-# Create a gzipped copy of each generated file. Cheap server-side optimization.
+# Expert setting! Create a gzipped copy of each generated file. Cheap server-
+# side optimization for very high traffic sites or low memory servers.
# GZIP_FILES = False
# File extensions that will be compressed
-# GZIP_EXTENSIONS = ('.txt', '.htm', '.html', '.css', '.js', '.json')
+# GZIP_EXTENSIONS = ('.txt', '.htm', '.html', '.css', '.js', '.json', '.xml')
+# Use an external gzip command? None means no.
+# Example: GZIP_COMMAND = "pigz -k {filename}"
+# GZIP_COMMAND = None
+# Make sure the server does not return a "Accept-Ranges: bytes" header for
+# files compressed by this option! OR make sure that a ranged request does not
+# return partial content of another representation for these resources. Do not
+# use this feature if you do not understand what this means.
+
+# Compiler to process LESS files.
+# LESS_COMPILER = 'lessc'
+
+# A list of options to pass to the LESS compiler.
+# Final command is: LESS_COMPILER LESS_OPTIONS file.less
+# LESS_OPTIONS = []
+
+# Compiler to process Sass files.
+# SASS_COMPILER = 'sass'
+
+# A list of options to pass to the Sass compiler.
+# Final command is: SASS_COMPILER SASS_OPTIONS file.s(a|c)ss
+# SASS_OPTIONS = []
# #############################################################################
# Image Gallery Options
@@ -224,31 +321,50 @@ COMPILERS = {
# THUMBNAIL_SIZE = 180
# MAX_IMAGE_SIZE = 1280
# USE_FILENAME_AS_TITLE = True
+# EXTRA_IMAGE_EXTENSIONS = []
+#
+# If set to False, it will sort by filename instead. Defaults to True
+# GALLERY_SORT_BY_DATE = True
# #############################################################################
# HTML fragments and diverse things that are used by the templates
# #############################################################################
-# Data about post-per-page indexes
-# INDEXES_TITLE = "" # If this is empty, the default is BLOG_TITLE
-# INDEXES_PAGES = "" # If this is empty, the default is 'old posts page %d' translated
+# Data about post-per-page indexes.
+# INDEXES_PAGES defaults to 'old posts, page %d' or 'page %d' (translated),
+# depending on the value of INDEXES_PAGES_MAIN.
+# INDEXES_TITLE = "" # If this is empty, defaults to BLOG_TITLE
+# INDEXES_PAGES = "" # If this is empty, defaults to '[old posts,] page %d' (see above)
+# INDEXES_PAGES_MAIN = False # If True, INDEXES_PAGES is also displayed on
+# # the main (the newest) index page (index.html)
+
+# Name of the theme to use.
+THEME = "bootstrap3"
-# Name of the theme to use. Themes are located in themes/theme_name
-# THEME = 'site'
+# Color scheme to be used for code blocks. If your theme provides
+# "assets/css/code.css" this is ignored.
+# Can be any of autumn borland bw colorful default emacs friendly fruity manni
+# monokai murphy native pastie perldoc rrt tango trac vim vs
+# CODE_COLOR_SCHEME = 'default'
# If you use 'site-reveal' theme you can select several subthemes
-# THEME_REVEAL_CONGIF_SUBTHEME = 'sky' # You can also use: beige/serif/simple/night/default
+# THEME_REVEAL_CONFIG_SUBTHEME = 'sky'
+# You can also use: beige/serif/simple/night/default
-# Again, if you use 'site-reveal' theme you can select several transitions between the slides
-# THEME_REVEAL_CONGIF_TRANSITION = 'cube' # You can also use: page/concave/linear/none/default
+# Again, if you use 'site-reveal' theme you can select several transitions
+# between the slides
+# THEME_REVEAL_CONFIG_TRANSITION = 'cube'
+# You can also use: page/concave/linear/none/default
-# date format used to display post dates. (str used by datetime.datetime.strftime)
+# date format used to display post dates.
+# (str used by datetime.datetime.strftime)
# DATE_FORMAT = '%Y-%m-%d %H:%M'
# FAVICONS contains (name, file, size) tuples.
# Used for create favicon link like this:
# <link rel="name" href="file" sizes="size"/>
-# about favicons, see: http://www.netmagazine.com/features/create-perfect-favicon
+# For creating favicons, take a look at:
+# http://www.netmagazine.com/features/create-perfect-favicon
# FAVICONS = {
# ("icon", "/favicon.ico", "16x16"),
# ("icon", "/icon_128x128.png", "128x128"),
@@ -257,7 +373,17 @@ COMPILERS = {
# Show only teasers in the index pages? Defaults to False.
# INDEX_TEASERS = False
-# A HTML fragment describing the license, for the sidebar. Default is "".
+# A HTML fragment with the Read more... link.
+# The following tags exist and are replaced for you:
+# {link} A link to the full post page.
+# {read_more} The string “Read more” in the current language.
+# {{ A literal { (U+007B LEFT CURLY BRACKET)
+# }} A literal } (U+007D RIGHT CURLY BRACKET)
+# READ_MORE_LINK = '<p class="more"><a href="{link}">{read_more}…</a></p>'
+
+# A HTML fragment describing the license, for the sidebar.
+# (translatable)
+LICENSE = ""
# I recommend using the Creative Commons' wizard:
# http://creativecommons.org/choose/
# LICENSE = """
@@ -267,17 +393,48 @@ COMPILERS = {
# src="http://i.creativecommons.org/l/by-nc-sa/2.5/ar/88x31.png"></a>"""
# A small copyright notice for the page footer (in HTML).
-# Default is ''
-CONTENT_FOOTER = 'Contents &copy; {date} <a href="mailto:{email}">{author}</a> - Powered by <a href="http://nikola.ralsina.com.ar">Nikola</a>'
-CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
- author=BLOG_AUTHOR,
- date=time.gmtime().tm_year)
-
-# To enable comments via Disqus, you need to create a forum at
-# http://disqus.com, and set DISQUS_FORUM to the short name you selected.
-# If you want to disable comments, set it to False.
-# Default is "nikolademo", used by the demo sites
-# DISQUS_FORUM = "nikolademo"
+# (translatable)
+CONTENT_FOOTER = 'Contents &copy; {date} <a href="mailto:{email}">{author}</a> - Powered by <a href="http://getnikola.com" rel="nofollow">Nikola</a> {license}'
+
+# Things that will be passed to CONTENT_FOOTER.format(). This is done
+# for translatability, as dicts are not formattable. Nikola will
+# intelligently format the setting properly.
+# The setting takes a dict. The keys are languages. The values are
+# tuples of tuples of positional arguments and dicts of keyword arguments
+# to format(). For example, {'en': (('Hello'), {'target': 'World'})}
+# results in CONTENT_FOOTER['en'].format('Hello', target='World').
+# WARNING: If you do not use multiple languages with CONTENT_FOOTER, this
+# still needs to be a dict of this format. (it can be empty if you
+# do not need formatting)
+# (translatable)
+CONTENT_FOOTER_FORMATS = {
+ DEFAULT_LANG: (
+ (),
+ {
+ "email": BLOG_EMAIL,
+ "author": BLOG_AUTHOR,
+ "date": time.gmtime().tm_year,
+ "license": LICENSE
+ }
+ )
+}
+
+# To use comments, you can choose between different third party comment
+# systems, one of "disqus", "livefyre", "intensedebate", "moot",
+# "googleplus", "facebook" or "isso"
+COMMENT_SYSTEM = "disqus"
+# And you also need to add your COMMENT_SYSTEM_ID which
+# depends on what comment system you use. The default is
+# "nikolademo" which is a test account for Disqus. More information
+# is in the manual.
+COMMENT_SYSTEM_ID = "nikolademo"
+
+# Enable annotations using annotateit.org?
+# If set to False, you can still enable them for individual posts and pages
+# setting the "annotations" metadata.
+# If set to True, you can disable them for individual posts and pages using
+# the "noannotations" metadata.
+# ANNOTATIONS = False
# Create index.html for story folders?
# STORY_INDEX = False
@@ -286,28 +443,106 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# Enable comments on picture gallery pages?
# COMMENTS_IN_GALLERIES = False
+# What file should be used for directory indexes?
+# Defaults to index.html
+# Common other alternatives: default.html for IIS, index.php
+# INDEX_FILE = "index.html"
+
+# If a link ends in /index.html, drop the index.html part.
+# http://mysite/foo/bar/index.html => http://mysite/foo/bar/
+# (Uses the INDEX_FILE setting, so if that is, say, default.html,
+# it will instead /foo/default.html => /foo)
+# (Note: This was briefly STRIP_INDEX_HTML in v 5.4.3 and 5.4.4)
+# Default = False
+# STRIP_INDEXES = False
+
+# Should the sitemap list directories which only include other directories
+# and no files.
+# Default to True
+# If this is False
+# e.g. /2012 includes only /01, /02, /03, /04, ...: don't add it to the sitemap
+# if /2012 includes any files (including index.html)... add it to the sitemap
+# SITEMAP_INCLUDE_FILELESS_DIRS = True
+
+# Instead of putting files in <slug>.html, put them in
+# <slug>/index.html. Also enables STRIP_INDEXES
+# This can be disabled on a per-page/post basis by adding
+# .. pretty_url: False
+# to the metadata
+# PRETTY_URLS = False
+
+# If True, publish future dated posts right away instead of scheduling them.
+# Defaults to False.
+# FUTURE_IS_NOW = False
+
+# If True, future dated posts are allowed in deployed output
+# Only the individual posts are published/deployed; not in indexes/sitemap
+# Generally, you want FUTURE_IS_NOW and DEPLOY_FUTURE to be the same value.
+# DEPLOY_FUTURE = False
+# If False, draft posts will not be deployed
+# DEPLOY_DRAFTS = True
+
+# Allows scheduling of posts using the rule specified here (new_post -s)
+# Specify an iCal Recurrence Rule: http://www.kanzaki.com/docs/ical/rrule.html
+# SCHEDULE_RULE = ''
+# If True, use the scheduling rule to all posts by default
+# SCHEDULE_ALL = False
+# If True, schedules post to today if possible, even if scheduled hour is over
+# SCHEDULE_FORCE_TODAY = False
+
# Do you want a add a Mathjax config file?
# MATHJAX_CONFIG = ""
# If you are using the compile-ipynb plugin, just add this one:
-#MATHJAX_CONFIG = """
-#<script type="text/x-mathjax-config">
-#MathJax.Hub.Config({
-# tex2jax: {
-# inlineMath: [ ['$','$'], ["\\\(","\\\)"] ],
-# displayMath: [ ['$$','$$'], ["\\\[","\\\]"] ]
-# },
-# displayAlign: 'left', // Change this to 'center' to center equations.
-# "HTML-CSS": {
-# styles: {'.MathJax_Display': {"margin": 0}}
-# }
-#});
-#</script>
-#"""
-
-# Enable Addthis social buttons?
-# Defaults to true
-# ADD_THIS_BUTTONS = True
+# MATHJAX_CONFIG = """
+# <script type="text/x-mathjax-config">
+# MathJax.Hub.Config({
+# tex2jax: {
+# inlineMath: [ ['$','$'], ["\\\(","\\\)"] ],
+# displayMath: [ ['$$','$$'], ["\\\[","\\\]"] ]
+# },
+# displayAlign: 'left', // Change this to 'center' to center equations.
+# "HTML-CSS": {
+# styles: {'.MathJax_Display': {"margin": 0}}
+# }
+# });
+# </script>
+# """
+
+# Do you want to customize the nbconversion of your IPython notebook?
+# IPYNB_CONFIG = {}
+# With the following example configuracion you can use a custom jinja template
+# called `toggle.tpl` which has to be located in your site/blog main folder:
+# IPYNB_CONFIG = {'Exporter':{'template_file': 'toggle'}}
+
+# What MarkDown extensions to enable?
+# You will also get gist, nikola and podcast because those are
+# done in the code, hope you don't mind ;-)
+# MARKDOWN_EXTENSIONS = ['fenced_code', 'codehilite']
+
+# Social buttons. This is sample code for AddThis (which was the default for a
+# long time). Insert anything you want here, or even make it empty.
+# (translatable)
+# SOCIAL_BUTTONS_CODE = """
+# <!-- Social buttons -->
+# <div id="addthisbox" class="addthis_toolbox addthis_peekaboo_style addthis_default_style addthis_label_style addthis_32x32_style">
+# <a class="addthis_button_more">Share</a>
+# <ul><li><a class="addthis_button_facebook"></a>
+# <li><a class="addthis_button_google_plusone_share"></a>
+# <li><a class="addthis_button_linkedin"></a>
+# <li><a class="addthis_button_twitter"></a>
+# </ul>
+# </div>
+# <script src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script>
+# <!-- End of social buttons -->
+# """
+
+# Show link to source for the posts?
+# Formerly known as HIDE_SOURCELINK (inverse)
+# SHOW_SOURCELINK = True
+# Copy the source files for your pages?
+# Setting it to False implies SHOW_SOURCELINK = False
+# COPY_SOURCES = True
# Modify the number of Post per Index Page
# Defaults to 10
@@ -321,30 +556,73 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# Show only teasers in the RSS feed? Default to True
# RSS_TEASERS = True
+# Strip HTML in the RSS feed? Default to False
+# RSS_PLAIN = False
+
# A search form to search this site, for the sidebar. You can use a google
# custom search (http://www.google.com/cse/)
# Or a duckduckgo search: https://duckduckgo.com/search_box.html
# Default is no search form.
+# (translatable)
# SEARCH_FORM = ""
#
-# This search form works for any site and looks good in the "site" theme where it
-# appears on the navigation bar
-#SEARCH_FORM = """
-#<!-- Custom search -->
-#<form method="get" id="search" action="http://duckduckgo.com/"
-# class="navbar-form pull-left">
-#<input type="hidden" name="sites" value="%s"/>
-#<input type="hidden" name="k8" value="#444444"/>
-#<input type="hidden" name="k9" value="#D51920"/>
-#<input type="hidden" name="kt" value="h"/>
-#<input type="text" name="q" maxlength="255"
-# placeholder="Search&hellip;" class="span2" style="margin-top: 4px;"/>
-#<input type="submit" value="DuckDuckGo Search" style="visibility: hidden;" />
-#</form>
-#<!-- End of custom search -->
-#""" % BLOG_URL
+# This search form works for any site and looks good in the "site" theme where
+# it appears on the navigation bar:
+#
+# SEARCH_FORM = """
+# <!-- Custom search -->
+# <form method="get" id="search" action="//duckduckgo.com/"
+# class="navbar-form pull-left">
+# <input type="hidden" name="sites" value="%s"/>
+# <input type="hidden" name="k8" value="#444444"/>
+# <input type="hidden" name="k9" value="#D51920"/>
+# <input type="hidden" name="kt" value="h"/>
+# <input type="text" name="q" maxlength="255"
+# placeholder="Search&hellip;" class="span2" style="margin-top: 4px;"/>
+# <input type="submit" value="DuckDuckGo Search" style="visibility: hidden;" />
+# </form>
+# <!-- End of custom search -->
+# """ % SITE_URL
+#
+# If you prefer a google search form, here's an example that should just work:
+# SEARCH_FORM = """
+# <!-- Custom search with google-->
+# <form id="search" action="//www.google.com/search" method="get" class="navbar-form pull-left">
+# <input type="hidden" name="q" value="site:%s" />
+# <input type="text" name="q" maxlength="255" results="0" placeholder="Search"/>
+# </form>
+# <!-- End of custom search -->
+# """ % SITE_URL
+
+# Also, there is a local search plugin you can use, based on Tipue, but it requires setting several
+# options:
+
+# SEARCH_FORM = """
+# <span class="navbar-form pull-left">
+# <input type="text" id="tipue_search_input">
+# </span>"""
#
-# Also, there is a local search plugin you can use.
+# BODY_END = """
+# <script src="/assets/js/tipuesearch_set.js"></script>
+# <script src="/assets/js/tipuesearch.js"></script>
+# <script>
+# $(document).ready(function() {
+# $('#tipue_search_input').tipuesearch({
+# 'mode': 'json',
+# 'contentLocation': '/assets/js/tipuesearch_content.json',
+# 'showUrl': false
+# });
+# });
+# </script>
+# """
+
+# EXTRA_HEAD_DATA = """
+# <link rel="stylesheet" type="text/css" href="/assets/css/tipuesearch.css">
+# <div id="tipue_search_content" style="margin-left: auto; margin-right: auto; padding: 20px;"></div>
+# """
+# ENABLED_EXTRAS = ['local_search']
+#
+
# Use content distribution networks for jquery and twitter-bootstrap css and js
# If this is True, jquery is served from the Google CDN and twitter-bootstrap
@@ -353,13 +631,14 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# external resources.
# USE_CDN = False
-# Google analytics script or whatever else you use. Added to the bottom of <body>
+# Extra things you want in the pages HEAD tag. This will be added right
+# before </head>
+# (translatable)
+# EXTRA_HEAD_DATA = ""
+# Google Analytics or whatever else you use. Added to the bottom of <body>
# in the default template (base.tmpl).
-# ANALYTICS = ""
-
-# HTML snippet that will be added at the bottom of body of <body>
-# in the default template (base.tmpl).
-# SOCIAL_BUTTONS_CODE = ""
+# (translatable)
+# BODY_END = ""
# The possibility to extract metadata from the filename by using a
# regular expression.
@@ -376,13 +655,17 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# '(?P<date>\d{4}-\d{2}-\d{2})-(?P<slug>.*)-(?P<title>.*)\.md'
# FILE_METADATA_REGEXP = None
+# Additional metadata that is added to a post when creating a new_post
+# ADDITIONAL_METADATA = {}
+
# Nikola supports Twitter Card summaries / Open Graph.
# Twitter cards make it possible for you to attach media to Tweets
# that link to your content.
#
# IMPORTANT:
# Please note, that you need to opt-in for using Twitter Cards!
-# To do this please visit https://dev.twitter.com/form/participate-twitter-cards
+# To do this please visit
+# https://dev.twitter.com/form/participate-twitter-cards
#
# Uncomment and modify to following lines to match your accounts.
# Specifying the id for either 'site' or 'creator' will be preferred
@@ -391,16 +674,22 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# TWITTER_CARD = {
# # 'use_twitter_cards': True, # enable Twitter Cards / Open Graph
# # 'site': '@website', # twitter nick for the website
-# # 'site:id': 123456, # Same as site, but the website's Twitter user ID instead.
+# # 'site:id': 123456, # Same as site, but the website's Twitter user ID
+# # instead.
# # 'creator': '@username', # Username for the content creator / author.
# # 'creator:id': 654321, # Same as creator, but the Twitter user's ID.
# }
-# If you want to use formatted post time in W3C-DTF Format(ex. 2012-03-30T23:00:00+02:00),
-# set timzone if you want a localized posted date.
+# Post's dates are considered in UTC by default, if you want to use
+# another time zone, please set TIMEZONE to match. Check the available
+# list from Wikipedia:
+# http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+# (eg. 'Europe/Zurich')
+# Also, if you want to use a different time zone in some of your posts,
+# you can use W3C-DTF Format (ex. 2012-03-30T23:00:00+02:00)
#
-# TIMEZONE = 'Europe/Zurich'
+# TIMEZONE = 'UTC'
# If webassets is installed, bundle JS and CSS to make site loading faster
# USE_BUNDLES = True
@@ -408,7 +697,56 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL,
# Plugins you don't want to use. Be careful :-)
# DISABLED_PLUGINS = ["render_galleries"]
+# Add the absolute paths to directories containing plugins to use them.
+# For example, the `plugins` directory of your clone of the Nikola plugins
+# repository.
+# EXTRA_PLUGINS_DIRS = []
+
+# Experimental plugins - use at your own risk.
+# They probably need some manual adjustments - please see their respective
+# readme.
+# ENABLED_EXTRAS = [
+# 'planetoid',
+# 'ipynb',
+# 'local_search',
+# 'render_mustache',
+# ]
+
+# List of regular expressions, links matching them will always be considered
+# valid by "nikola check -l"
+# LINK_CHECK_WHITELIST = []
+
+# If set to True, enable optional hyphenation in your posts (requires pyphen)
+# HYPHENATE = False
+
+# The <hN> tags in HTML generated by certain compilers (reST/Markdown)
+# will be demoted by that much (1 → h1 will become h2 and so on)
+# This was a hidden feature of the Markdown and reST compilers in the
+# past. Useful especially if your post titles are in <h1> tags too, for
+# example.
+# (defaults to 1.)
+# DEMOTE_HEADERS = 1
+
+# You can configure the logging handlers installed as plugins or change the
+# log level of the default stdout handler.
+LOGGING_HANDLERS = {
+ 'stderr': {'loglevel': 'WARNING', 'bubble': True},
+ # 'smtp': {
+ # 'from_addr': 'test-errors@example.com',
+ # 'recipients': ('test@example.com'),
+ # 'credentials':('testusername', 'password'),
+ # 'server_addr': ('127.0.0.1', 25),
+ # 'secure': (),
+ # 'level': 'DEBUG',
+ # 'bubble': True
+ # }
+}
+
+# Templates will use those filters, along with the defaults.
+# Consult your engine's documentation on filters if you need help defining
+# those.
+# TEMPLATE_FILTERS = {}
+
# Put in global_context things you want available on all your templates.
# It can be anything, data, functions, modules, etc.
-
GLOBAL_CONTEXT = {}
diff --git a/tests/data/translated_titles/stories/1.txt.pl b/tests/data/translated_titles/stories/1.pl.txt
index a888c1f..a888c1f 100644
--- a/tests/data/translated_titles/stories/1.txt.pl
+++ b/tests/data/translated_titles/stories/1.pl.txt
diff --git a/tests/test_command_import_wordpress.py b/tests/test_command_import_wordpress.py
index 04e0631..1a2e7d9 100644
--- a/tests/test_command_import_wordpress.py
+++ b/tests/test_command_import_wordpress.py
@@ -469,5 +469,6 @@ You can use the <a title="Jenkins Plugin: Violations" href="https://wiki.jenkins
self.assertEqual(1, len(redirections))
self.assertTrue(('somewhere/else/index.html', '/posts/somewhereelse.html') in redirections)
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_command_init.py b/tests/test_command_init.py
index 4332213..d2171f8 100644
--- a/tests/test_command_init.py
+++ b/tests/test_command_init.py
@@ -11,13 +11,18 @@ import unittest
import mock
import nikola
+from nikola.plugins.command.init import SAMPLE_CONF
+from nikola.plugins.command.init import format_default_translations_config
class CommandInitCallTest(unittest.TestCase):
def setUp(self):
+ self.ask_questions = mock.MagicMock()
self.copy_sample_site = mock.MagicMock()
self.create_configuration = mock.MagicMock()
self.create_empty_site = mock.MagicMock()
+ ask_questions_patch = mock.patch(
+ 'nikola.plugins.command.init.CommandInit.ask_questions', self.ask_questions)
copy_sample_site_patch = mock.patch(
'nikola.plugins.command.init.CommandInit.copy_sample_site', self.copy_sample_site)
create_configuration_patch = mock.patch(
@@ -25,8 +30,8 @@ class CommandInitCallTest(unittest.TestCase):
create_empty_site_patch = mock.patch(
'nikola.plugins.command.init.CommandInit.create_empty_site', self.create_empty_site)
- self.patches = [copy_sample_site_patch, create_configuration_patch,
- create_empty_site_patch]
+ self.patches = [ask_questions_patch, copy_sample_site_patch,
+ create_configuration_patch, create_empty_site_patch]
for patch in self.patches:
patch.start()
@@ -42,16 +47,26 @@ class CommandInitCallTest(unittest.TestCase):
del self.create_empty_site
def test_init_default(self):
- for arguments in (dict(options={'demo': True}, args=['destination']), {}):
- self.init_command.execute(**arguments)
+ self.init_command.execute()
- self.assertTrue(self.create_configuration.called)
- self.assertTrue(self.copy_sample_site.called)
- self.assertFalse(self.create_empty_site.called)
+ self.assertTrue(self.ask_questions.called)
+ self.assertTrue(self.create_configuration.called)
+ self.assertFalse(self.copy_sample_site.called)
+ self.assertTrue(self.create_empty_site.called)
- def test_init_called_without_target(self):
- self.init_command.execute()
+ def test_init_args(self):
+ arguments = dict(options={'demo': True, 'quiet': True}, args=['destination'])
+ self.init_command.execute(**arguments)
+ self.assertFalse(self.ask_questions.called)
+ self.assertTrue(self.create_configuration.called)
+ self.assertTrue(self.copy_sample_site.called)
+ self.assertFalse(self.create_empty_site.called)
+
+ def test_init_called_without_target_quiet(self):
+ self.init_command.execute(**dict(options={'quiet': True}))
+
+ self.assertFalse(self.ask_questions.called)
self.assertFalse(self.create_configuration.called)
self.assertFalse(self.copy_sample_site.called)
self.assertFalse(self.create_empty_site.called)
@@ -59,10 +74,34 @@ class CommandInitCallTest(unittest.TestCase):
def test_init_empty_dir(self):
self.init_command.execute(args=['destination'])
+ self.assertTrue(self.ask_questions.called)
self.assertTrue(self.create_configuration.called)
self.assertFalse(self.copy_sample_site.called)
self.assertTrue(self.create_empty_site.called)
+class InitHelperTests(unittest.TestCase):
+ """Test helper functions provided with the init command."""
+
+ def test_configure_translations_without_additional_languages(self):
+ """
+ Testing the configuration of the translation when no additional language has been found.
+ """
+ translations_cfg = format_default_translations_config(set())
+ self.assertEqual(SAMPLE_CONF["TRANSLATIONS"], translations_cfg)
+
+ def test_configure_translations_with_2_additional_languages(self):
+ """
+ Testing the configuration of the translation when no additional language has been found.
+ """
+ translations_cfg = format_default_translations_config(
+ set(["es", "en"]))
+ self.assertEqual("""{
+ DEFAULT_LANG: "",
+ "en": "./en",
+ "es": "./es",
+}""", translations_cfg)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_commands.py b/tests/test_commands.py
new file mode 100644
index 0000000..5c2370a
--- /dev/null
+++ b/tests/test_commands.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals, absolute_import
+
+# This code is so you can run the samples without installing the package,
+# and should be before any import touching nikola, in any file under tests/
+import os
+import sys
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
+
+import unittest
+
+from nikola.plugins.command.version import CommandVersion
+
+
+class CommandVersionCallTest(unittest.TestCase):
+ def test_version(self):
+ """Test `nikola version`."""
+ CommandVersion().execute()
diff --git a/tests/test_compile_markdown.py b/tests/test_compile_markdown.py
index d51d3aa..ace17cf 100644
--- a/tests/test_compile_markdown.py
+++ b/tests/test_compile_markdown.py
@@ -15,16 +15,10 @@ import unittest
from os import path
from nikola.plugins.compile.markdown import CompileMarkdown
+from .base import BaseTestCase, FakeSite
-class FakeSite(object):
- config = {
- "MARKDOWN_EXTENSIONS": ['fenced_code', 'codehilite'],
- "LOGGING_HANDLERS": {'stderr': {'loglevel': 'WARNING', 'bubble': True}}
- }
-
-
-class CompileMarkdownTests(unittest.TestCase):
+class CompileMarkdownTests(BaseTestCase):
def setUp(self):
self.tmp_dir = tempfile.mkdtemp()
self.input_path = path.join(self.tmp_dir, 'input.markdown')
@@ -61,9 +55,9 @@ class CompileMarkdownTests(unittest.TestCase):
expected_output = '''\
<table class="codehilitetable"><tr><td class="linenos">\
<div class="linenodiv"><pre>1</pre></div>\
-</td><td class="code"><div class="code">\
-<pre><span class="kn">from</span> <span class="nn">this</span>
-</pre></div>
+</td><td class="code"><pre class="code literal-block">\
+<span class="kn">from</span> <span class="nn">this</span>
+</pre>
</td></tr></table>
'''
diff --git a/tests/test_integration.py b/tests/test_integration.py
index 44b28e9..9f982d8 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -7,15 +7,15 @@ import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
-
import codecs
import locale
import shutil
+import subprocess
import tempfile
import unittest
import lxml.html
-from nose.plugins.skip import SkipTest
+import pytest
from nikola import __main__
import nikola
@@ -33,6 +33,7 @@ class EmptyBuildTest(BaseTestCase):
@classmethod
def setUpClass(cls):
"""Setup a demo site."""
+ cls.startdir = os.getcwd()
cls.tmpdir = tempfile.mkdtemp()
cls.target_dir = os.path.join(cls.tmpdir, "target")
cls.init_command = nikola.plugins.command.init.CommandInit()
@@ -69,6 +70,8 @@ class EmptyBuildTest(BaseTestCase):
@classmethod
def tearDownClass(self):
"""Remove the demo site."""
+ # Don't saw off the branch you're sitting on!
+ os.chdir(self.startdir)
# ignore_errors=True for windows by issue #782
shutil.rmtree(self.tmpdir, ignore_errors=(sys.platform == 'win32'))
# Fixes Issue #438
@@ -182,9 +185,18 @@ class TranslatedBuildTest(EmptyBuildTest):
def __init__(self, *a, **kw):
super(TranslatedBuildTest, self).__init__(*a, **kw)
try:
+ self.oldlocale = locale.getlocale()
locale.setlocale(locale.LC_ALL, ("pl_PL", "utf8"))
except:
- raise SkipTest
+ pytest.skip()
+
+ @classmethod
+ def tearDownClass(self):
+ try:
+ locale.setlocale(locale.LC_ALL, self.oldlocale)
+ except:
+ pass
+ super(TranslatedBuildTest, self).tearDownClass()
def test_translated_titles(self):
"""Check that translated title is picked up."""
@@ -207,15 +219,15 @@ class TranslationsPatternTest1(TranslatedBuildTest):
@classmethod
def patch_site(self):
- """Set the TRANSLATIONS_PATTERN to the new v7 default"""
- os.rename(os.path.join(self.target_dir, "stories", "1.txt.pl"),
- os.path.join(self.target_dir, "stories", "1.pl.txt")
+ """Set the TRANSLATIONS_PATTERN to the old v6 default"""
+ os.rename(os.path.join(self.target_dir, "stories", "1.pl.txt"),
+ os.path.join(self.target_dir, "stories", "1.txt.pl")
)
conf_path = os.path.join(self.target_dir, "conf.py")
with codecs.open(conf_path, "rb", "utf-8") as inf:
data = inf.read()
- data = data.replace('TRANSLATIONS_PATTERN = "{path}.{ext}.{lang}"',
- 'TRANSLATIONS_PATTERN = "{path}.{lang}.{ext}"')
+ data = data.replace('TRANSLATIONS_PATTERN = "{path}.{lang}.{ext}"',
+ 'TRANSLATIONS_PATTERN = "{path}.{ext}.{lang}"')
with codecs.open(conf_path, "wb+", "utf8") as outf:
outf.write(data)
@@ -238,15 +250,15 @@ class TranslationsPatternTest2(TranslatedBuildTest):
@classmethod
def patch_site(self):
- """Set the TRANSLATIONS_PATTERN to the new v7 default"""
+ """Set the TRANSLATIONS_PATTERN to the old v6 default"""
conf_path = os.path.join(self.target_dir, "conf.py")
- os.rename(os.path.join(self.target_dir, "stories", "1.txt.pl"),
- os.path.join(self.target_dir, "stories", "1_pl.txt")
+ os.rename(os.path.join(self.target_dir, "stories", "1.pl.txt"),
+ os.path.join(self.target_dir, "stories", "1.txt.pl")
)
with codecs.open(conf_path, "rb", "utf-8") as inf:
data = inf.read()
- data = data.replace('TRANSLATIONS_PATTERN = "{path}.{ext}.{lang}"',
- 'TRANSLATIONS_PATTERN = "{path}_{lang}.{ext}"')
+ data = data.replace('TRANSLATIONS_PATTERN = "{path}.{lang}.{ext}"',
+ 'TRANSLATIONS_PATTERN = "{path}.{ext}.{lang}"')
with codecs.open(conf_path, "wb+", "utf8") as outf:
outf.write(data)
@@ -446,5 +458,49 @@ class SubdirRunningTest(DemoBuildTest):
self.assertEquals(result, 0)
+class InvariantBuildTest(EmptyBuildTest):
+ """Test that a default build of --demo works."""
+
+ @classmethod
+ def build(self):
+ """Build the site."""
+ try:
+ self.oldlocale = locale.getlocale()
+ locale.setlocale(locale.LC_ALL, ("en_US", "utf8"))
+ except:
+ pytest.skip('no en_US locale!')
+ else:
+ with cd(self.target_dir):
+ __main__.main(["build", "--invariant"])
+ finally:
+ try:
+ locale.setlocale(locale.LC_ALL, self.oldlocale)
+ except:
+ pass
+
+ @classmethod
+ def fill_site(self):
+ """Fill the site with demo content."""
+ self.init_command.copy_sample_site(self.target_dir)
+ self.init_command.create_configuration(self.target_dir)
+ os.system('rm "{0}/stories/creating-a-theme.rst" "{0}/stories/extending.txt" "{0}/stories/internals.txt" "{0}/stories/manual.rst" "{0}/stories/social_buttons.txt" "{0}/stories/theming.rst" "{0}/stories/upgrading-to-v6.txt"'.format(self.target_dir))
+
+ def test_invariance(self):
+ """Compare the output to the canonical output."""
+ if sys.version_info[0:2] != (2, 7):
+ pytest.skip('only python 2.7 is supported right now')
+ good_path = os.path.join(os.path.dirname(__file__), 'data', 'baseline{0[0]}.{0[1]}'.format(sys.version_info))
+ if not os.path.exists(good_path):
+ pytest.skip('no baseline found')
+ with cd(self.target_dir):
+ try:
+ diff = subprocess.check_output(['diff', '-ubwr', good_path, 'output'])
+ self.assertEqual(diff.strip(), '')
+ except subprocess.CalledProcessError as exc:
+ print('Unexplained diff for the invariance test. (-canonical +built)')
+ print(exc.output.decode('utf-8'))
+ self.assertEqual(exc.returncode, 0, 'Unexplained diff for the invariance test.')
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/tests/test_rss_feeds.py b/tests/test_rss_feeds.py
index c43b92b..3554a38 100644
--- a/tests/test_rss_feeds.py
+++ b/tests/test_rss_feeds.py
@@ -15,18 +15,21 @@ import os
import re
import unittest
+import dateutil.tz
+from lxml import etree
import mock
-from lxml import etree
from .base import LocaleSupportInTesting
-
import nikola
fake_conf = defaultdict(str)
fake_conf['TIMEZONE'] = 'UTC'
+fake_conf['__tzinfo__'] = dateutil.tz.tzutc()
fake_conf['DEFAULT_LANG'] = 'en'
fake_conf['TRANSLATIONS'] = {'en': ''}
fake_conf['BASE_URL'] = 'http://some.blog/'
+fake_conf['BLOG_AUTHOR'] = nikola.nikola.utils.TranslatableSetting('BLOG_AUTHOR', 'Nikola Tesla', ['en'])
+fake_conf['TRANSLATIONS_PATTERN'] = '{path}.{lang}.{ext}'
class FakeCompiler(object):
@@ -71,7 +74,8 @@ class RSSFeedTest(unittest.TestCase):
[example_post,
],
'testfeed.rss',
- True)
+ True,
+ False)
opener_mock.assert_called_once_with(
'testfeed.rss', 'wb+', 'utf-8')
diff --git a/tests/test_rst_compiler.py b/tests/test_rst_compiler.py
index ae4ac06..379aba2 100644
--- a/tests/test_rst_compiler.py
+++ b/tests/test_rst_compiler.py
@@ -43,85 +43,16 @@ import tempfile
import docutils
from lxml import html
-from nose.plugins.skip import SkipTest
+import pytest
import unittest
-from yapsy.PluginManager import PluginManager
-from nikola import utils
import nikola.plugins.compile.rest
from nikola.plugins.compile.rest import gist
from nikola.plugins.compile.rest import vimeo
import nikola.plugins.compile.rest.listing
from nikola.plugins.compile.rest.doc import Plugin as DocPlugin
-from nikola.utils import _reload, STDERR_HANDLER
-from nikola.plugin_categories import (
- Command,
- Task,
- LateTask,
- TemplateSystem,
- PageCompiler,
- TaskMultiplier,
- RestExtension,
-)
-from .base import BaseTestCase
-
-
-class FakePost(object):
-
- def __init__(self, title, slug):
- self._title = title
- self._slug = slug
- self._meta = {'slug': slug}
-
- def title(self):
- return self._title
-
- def meta(self, key):
- return self._meta[key]
-
- def permalink(self):
- return '/posts/' + self._slug
-
-
-class FakeSite(object):
- def __init__(self):
- self.template_system = self
- self.config = {
- 'DISABLED_PLUGINS': [],
- 'EXTRA_PLUGINS': [],
- 'DEFAULT_LANG': 'en',
- }
- self.EXTRA_PLUGINS = self.config['EXTRA_PLUGINS']
- self.plugin_manager = PluginManager(categories_filter={
- "Command": Command,
- "Task": Task,
- "LateTask": LateTask,
- "TemplateSystem": TemplateSystem,
- "PageCompiler": PageCompiler,
- "TaskMultiplier": TaskMultiplier,
- "RestExtension": RestExtension,
- })
- self.loghandlers = [STDERR_HANDLER]
- self.plugin_manager.setPluginInfoExtension('plugin')
- if sys.version_info[0] == 3:
- places = [
- os.path.join(os.path.dirname(utils.__file__), 'plugins'),
- ]
- else:
- places = [
- os.path.join(os.path.dirname(utils.__file__), utils.sys_encode('plugins')),
- ]
- self.plugin_manager.setPluginPlaces(places)
- self.plugin_manager.collectPlugins()
-
- self.timeline = [
- FakePost(title='Fake post',
- slug='fake-post')
- ]
- self.debug = True
-
- def render_template(self, name, _, context):
- return('<img src="IMG.jpg">')
+from nikola.utils import _reload
+from .base import BaseTestCase, FakeSite
class ReSTExtensionTestCase(BaseTestCase):
@@ -218,17 +149,17 @@ class GistTestCase(ReSTExtensionTestCase):
self.gist_type.get_raw_gist = lambda *_: "raw_gist"
_reload(nikola.plugins.compile.rest)
+ @pytest.mark.skipif(True, reason="This test indefinitely skipped.")
def test_gist(self):
""" Test the gist directive with filename """
- raise SkipTest
self.setHtmlFromRst(self.sample)
output = 'https://gist.github.com/fake_id.js?file=spam.py'
self.assertHTMLContains("script", attributes={"src": output})
self.assertHTMLContains("pre", text="raw_gist_file")
+ @pytest.mark.skipif(True, reason="This test indefinitely skipped.")
def test_gist_without_filename(self):
""" Test the gist directive without filename """
- raise SkipTest
self.setHtmlFromRst(self.sample_without_filename)
output = 'https://gist.github.com/fake_id2.js'
self.assertHTMLContains("script", attributes={"src": output})
@@ -295,7 +226,7 @@ class VimeoTestCase(ReSTExtensionTestCase):
""" Test Vimeo iframe tag generation """
self.basic_test()
self.assertHTMLContains("iframe",
- attributes={"src": ("http://player.vimeo.com/"
+ attributes={"src": ("//player.vimeo.com/"
"video/VID"),
"height": "400", "width": "600"})
@@ -309,7 +240,7 @@ class YoutubeTestCase(ReSTExtensionTestCase):
""" Test Youtube iframe tag generation """
self.basic_test()
self.assertHTMLContains("iframe",
- attributes={"src": ("http://www.youtube.com/"
+ attributes={"src": ("//www.youtube.com/"
"embed/YID?rel=0&hd=1&"
"wmode=transparent"),
"height": "400", "width": "600"})
@@ -323,11 +254,11 @@ class ListingTestCase(ReSTExtensionTestCase):
sample2 = '.. code-block:: python\n\n import antigravity'
sample3 = '.. sourcecode:: python\n\n import antigravity'
- #def test_listing(self):
- ##""" Test that we can render a file object contents without errors """
- ##with cd(os.path.dirname(__file__)):
- #self.deps = 'listings/nikola.py'
- #self.setHtmlFromRst(self.sample1)
+ # def test_listing(self):
+ # """ Test that we can render a file object contents without errors """
+ # with cd(os.path.dirname(__file__)):
+ # self.deps = 'listings/nikola.py'
+ # self.setHtmlFromRst(self.sample1)
def test_codeblock_alias(self):
""" Test CodeBlock aliases """
diff --git a/tests/test_scheduling.py b/tests/test_scheduling.py
index c9cda42..ae1cf92 100644
--- a/tests/test_scheduling.py
+++ b/tests/test_scheduling.py
@@ -1,16 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, absolute_import
-# This code is so you can run the samples without installing the package,
-# and should be before any import touching nikola, in any file under tests/
+import datetime
+import locale
import os
import sys
+# This code is so you can run the samples without installing the package,
+# and should be before any import touching nikola, in any file under tests/
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
+import dateutil.parser
+import dateutil.tz
+import pytest
from .base import BaseTestCase
-import datetime
-from nose.plugins.skip import SkipTest
+
try:
from freezegun import freeze_time
_freeze_time = True
@@ -18,127 +22,116 @@ except ImportError:
_freeze_time = False
freeze_time = lambda x: lambda y: y
-FMT = '%Y/%m/%d %H:%M:%S'
-NOW = '2013/08/22 10:00:00' # Thursday
-TODAY = datetime.datetime.strptime(NOW, FMT)
-RULE_TH = 'RRULE:FREQ=WEEKLY;BYDAY=TH'
-RULE_FR = 'RRULE:FREQ=WEEKLY;BYDAY=FR'
+_NOW = datetime.datetime( # Thursday
+ 2013, 8, 22, 10, 0, 0, tzinfo=dateutil.tz.tzutc())
+@pytest.mark.skipif(not _freeze_time, reason="freezegun not installed.")
class TestScheduling(BaseTestCase):
@classmethod
- def setUp(self):
- if not _freeze_time:
- raise SkipTest('freezegun not installed')
-
+ def setUp(cls):
d = [name for name in sys.modules if name.startswith("six.moves.")]
- self.deleted = {}
+ cls.deleted = {}
for name in d:
- self.deleted[name] = sys.modules[name]
+ cls.deleted[name] = sys.modules[name]
del sys.modules[name]
@classmethod
- def tearDown(self):
- for name, mod in self.deleted.items():
+ def tearDown(cls):
+ for name, mod in cls.deleted.items():
sys.modules[name] = mod
- @freeze_time(NOW)
+ @freeze_time(_NOW)
def test_get_date(self):
from nikola.plugins.command.new_post import get_date
- #### NOW does not match rule #########################################
- ## No last date
+ FMT = '%Y-%m-%d %H:%M:%S %Z'.format(
+ locale.nl_langinfo(locale.D_FMT),
+ locale.nl_langinfo(locale.T_FMT),
+ )
+ NOW = _NOW.strftime(FMT)
+ TODAY = dateutil.parser.parse(NOW)
+ RULE_TH = 'RRULE:FREQ=WEEKLY;BYDAY=TH'
+ RULE_FR = 'RRULE:FREQ=WEEKLY;BYDAY=FR'
+ UTC = dateutil.tz.tzutc()
+
+ # NOW does not match rule #########################################
+ # No last date
expected = TODAY.replace(day=23).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_FR))
- self.assertEqual(expected, get_date(True, RULE_FR, force_today=True))
+ self.assertEqual(expected, get_date(True, RULE_FR, tz=UTC))
+ self.assertEqual(expected, get_date(True, RULE_FR, tz=UTC))
- ## Last date in the past; doesn't match rule
+ # Last date in the past; doesn't match rule
date = TODAY.replace(hour=7)
expected = TODAY.replace(day=23, hour=7).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_FR, date))
- self.assertEqual(expected, get_date(True, RULE_FR, date, True))
+ self.assertEqual(expected, get_date(True, RULE_FR, date, tz=UTC))
- ## Last date in the future; doesn't match rule
+ # Last date in the future; doesn't match rule
date = TODAY.replace(day=24, hour=7)
expected = TODAY.replace(day=30, hour=7).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_FR, date))
- self.assertEqual(expected, get_date(True, RULE_FR, date, True))
+ self.assertEqual(expected, get_date(True, RULE_FR, date, tz=UTC))
- ## Last date in the past; matches rule
+ # Last date in the past; matches rule
date = TODAY.replace(day=16, hour=8)
expected = TODAY.replace(day=23, hour=8).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_FR, date))
- self.assertEqual(expected, get_date(True, RULE_FR, date, True))
+ self.assertEqual(expected, get_date(True, RULE_FR, date, tz=UTC))
- ## Last date in the future; matches rule
+ # Last date in the future; matches rule
date = TODAY.replace(day=23, hour=18)
expected = TODAY.replace(day=30, hour=18).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_FR, date))
- self.assertEqual(expected, get_date(True, RULE_FR, date, True))
-
- #### NOW matches rule ################################################
- ## Not scheduling should return NOW
- self.assertEqual(NOW, get_date(False, RULE_TH))
- ## No last date
- self.assertEqual(NOW, get_date(True, RULE_TH))
- self.assertEqual(NOW, get_date(True, RULE_TH, force_today=True))
-
- ## Last date in the past; doesn't match rule
- ### Corresponding time has already passed, today
+ self.assertEqual(expected, get_date(True, RULE_FR, date, tz=UTC))
+
+ # NOW matches rule ################################################
+ # Not scheduling should return NOW
+ self.assertEqual(NOW, get_date(False, RULE_TH, tz=UTC))
+ # No last date
+ self.assertEqual(NOW, get_date(True, RULE_TH, tz=UTC))
+ self.assertEqual(NOW, get_date(True, RULE_TH, tz=UTC))
+
+ # Last date in the past; doesn't match rule
+ # Corresponding time has already passed, today
date = TODAY.replace(day=21, hour=7)
expected = TODAY.replace(day=29, hour=7).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH, date))
- expected = TODAY.replace(day=22, hour=7).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH, date, True))
- ### Corresponding time has not passed today
+ self.assertEqual(expected, get_date(True, RULE_TH, date, tz=UTC))
+ # Corresponding time has not passed today
date = TODAY.replace(day=21, hour=18)
expected = TODAY.replace(day=22, hour=18).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH, date))
- self.assertEqual(expected, get_date(True, RULE_TH, date, True))
+ self.assertEqual(expected, get_date(True, RULE_TH, date, tz=UTC))
- ## Last date in the future; doesn't match rule
- ### Corresponding time has already passed, today
+ # Last date in the future; doesn't match rule
+ # Corresponding time has already passed, today
date = TODAY.replace(day=24, hour=7)
expected = TODAY.replace(day=29, hour=7).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH, date))
- self.assertEqual(expected, get_date(True, RULE_TH, date, True))
- ### Corresponding time has not passed today
+ self.assertEqual(expected, get_date(True, RULE_TH, date, tz=UTC))
+ # Corresponding time has not passed today
date = TODAY.replace(day=24, hour=18)
expected = TODAY.replace(day=29, hour=18).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH, date))
- self.assertEqual(expected, get_date(True, RULE_TH, date, True))
+ self.assertEqual(expected, get_date(True, RULE_TH, date, tz=UTC))
- ## Last date in the past; matches rule
- ### Corresponding time has already passed, today
+ # Last date in the past; matches rule
+ # Corresponding time has already passed, today
date = TODAY.replace(day=15, hour=7)
expected = TODAY.replace(day=29, hour=7).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH, date))
- expected = TODAY.replace(day=22, hour=7).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH, date, True))
- ### Corresponding time has already passed, today; rule specifies HOUR
+ self.assertEqual(expected, get_date(True, RULE_TH, date, tz=UTC))
+ # Corresponding time has already passed, today; rule specifies HOUR
date = TODAY.replace(day=15, hour=7)
expected = TODAY.replace(day=29, hour=9).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH + ';BYHOUR=9', date))
- expected = TODAY.replace(day=22, hour=9).strftime(FMT)
- self.assertEqual(expected,
- get_date(True, RULE_TH + ';BYHOUR=9', date, True))
- ### Corresponding time has not passed today
+ self.assertEqual(expected, get_date(True, RULE_TH + ';BYHOUR=9', date, tz=UTC))
+ # Corresponding time has not passed today
date = TODAY.replace(day=15, hour=18)
expected = TODAY.replace(day=22, hour=18).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH, date))
- self.assertEqual(expected, get_date(True, RULE_TH, date, True))
+ self.assertEqual(expected, get_date(True, RULE_TH, date, tz=UTC))
- ## Last date in the future; matches rule
- ### Corresponding time has already passed, today
+ # Last date in the future; matches rule
+ # Corresponding time has already passed, today
date = TODAY.replace(day=29, hour=7)
expected = TODAY.replace(day=5, month=9, hour=7).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH, date))
- ### Corresponding time has not passed today
+ self.assertEqual(expected, get_date(True, RULE_TH, date, tz=UTC))
+ # Corresponding time has not passed today
date = TODAY.replace(day=22, hour=18)
expected = TODAY.replace(day=29, hour=18).strftime(FMT)
- self.assertEqual(expected, get_date(True, RULE_TH, date))
- self.assertEqual(expected, get_date(True, RULE_TH, date, True))
+ self.assertEqual(expected, get_date(True, RULE_TH, date, tz=UTC))
if __name__ == '__main__':
import unittest
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 5aeba19..44d309b 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -12,7 +12,7 @@ import unittest
import mock
import lxml.html
from nikola.post import get_meta
-from nikola.utils import demote_headers
+from nikola.utils import demote_headers, TranslatableSetting
class dummy(object):
@@ -234,5 +234,93 @@ class HeaderDemotionTest(unittest.TestCase):
self.assertEquals(lxml.html.tostring(outdoc), lxml.html.tostring(doc))
+class TranslatableSettingsTest(unittest.TestCase):
+ """Tests for translatable settings."""
+
+ def test_string_input(self):
+ """Tests for string input."""
+ inp = 'Fancy Blog'
+ S = TranslatableSetting('S', inp, {'xx': ''})
+ S.default_lang = 'xx'
+ S.lang = 'xx'
+
+ try:
+ u = unicode(S)
+ except NameError: # Python 3
+ u = str(S)
+
+ cn = S() #   no language specified
+ cr = S('xx') # real language specified
+ cf = S('zz') # fake language specified
+
+ self.assertEqual(inp, u)
+ self.assertEqual(inp, cn)
+ self.assertEqual(inp, cr)
+ self.assertEqual(inp, cf)
+ self.assertEqual(S.lang, 'xx')
+ self.assertEqual(S.default_lang, 'xx')
+
+ def test_dict_input(self):
+ """Tests for dict input."""
+ inp = {'xx': 'Fancy Blog',
+ 'zz': 'Schmancy Blog'}
+
+ S = TranslatableSetting('S', inp, {'xx': '', 'zz': ''})
+ S.default_lang = 'xx'
+ S.lang = 'xx'
+
+ try:
+ u = unicode(S)
+ except NameError: # Python 3
+ u = str(S)
+
+ cn = S()
+ cx = S('xx')
+ cz = S('zz')
+ cf = S('ff')
+
+ self.assertEqual(inp['xx'], u)
+ self.assertEqual(inp['xx'], cn)
+ self.assertEqual(inp['xx'], cx)
+ self.assertEqual(inp['zz'], cz)
+ self.assertEqual(inp['xx'], cf)
+
+ def test_dict_input_lang(self):
+ """Test dict input, with a language change along the way."""
+ inp = {'xx': 'Fancy Blog',
+ 'zz': 'Schmancy Blog'}
+
+ S = TranslatableSetting('S', inp, {'xx': '', 'zz': ''})
+ S.default_lang = 'xx'
+ S.lang = 'xx'
+
+ try:
+ u = unicode(S)
+ except NameError: # Python 3
+ u = str(S)
+
+ cn = S()
+
+ self.assertEqual(inp['xx'], u)
+ self.assertEqual(inp['xx'], cn)
+
+ # Change the language.
+ # WARNING: DO NOT set lang locally in real code! Set it globally
+ # instead! (TranslatableSetting.lang = ...)
+ # WARNING: TranslatableSetting.lang is used to override the current
+ # locale settings returned by LocaleBorg! Use with care!
+ S.lang = 'zz'
+
+ try:
+ u = unicode(S)
+ except NameError: # Python 3
+ u = str(S)
+
+ cn = S()
+
+ self.assertEqual(inp['zz'], u)
+ self.assertEqual(inp['zz'], cn)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/translations/nikola.messages/bg.po b/translations/nikola.messages/bg.po
index 631c86e..23816b4 100644
--- a/translations/nikola.messages/bg.po
+++ b/translations/nikola.messages/bg.po
@@ -4,6 +4,8 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# ivoarch <ivkuzev@gmail.com>, 2013
# ivoarch <ivkuzev@gmail.com>, 2013
msgid ""
@@ -11,7 +13,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Bulgarian (http://www.transifex.com/projects/p/nikola/language/bg/)\n"
"MIME-Version: 1.0\n"
@@ -35,6 +37,9 @@ msgstr "Категории"
msgid "Tags and Categories"
msgstr "Тагове и Категории"
+msgid "Comments"
+msgstr ""
+
msgid "Read more"
msgstr "Прочети още"
@@ -70,6 +75,9 @@ msgstr "Предишна публикация"
msgid "Also available in:"
msgstr "Също достъпно в:"
+msgid "Languages:"
+msgstr ""
+
msgid "Original site"
msgstr "Оригиналния сайт"
@@ -79,6 +87,9 @@ msgstr "Стари публикации"
msgid "Archive"
msgstr "Архив"
+msgid "Publication date"
+msgstr ""
+
msgid "Posted:"
msgstr "Публиковано:"
@@ -90,3 +101,9 @@ msgstr ""
msgid "No posts found."
msgstr ""
+
+msgid "RSS feed"
+msgstr ""
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/ca.po b/translations/nikola.messages/ca.po
index bbcefd0..1560a1f 100644
--- a/translations/nikola.messages/ca.po
+++ b/translations/nikola.messages/ca.po
@@ -4,6 +4,8 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# ralsina <ralsina@netmanagers.com.ar>, 2013
# ralsina <ralsina@netmanagers.com.ar>, 2013
msgid ""
@@ -11,7 +13,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Catalan (http://www.transifex.com/projects/p/nikola/language/ca/)\n"
"MIME-Version: 1.0\n"
@@ -35,6 +37,9 @@ msgstr ""
msgid "Tags and Categories"
msgstr ""
+msgid "Comments"
+msgstr ""
+
msgid "Read more"
msgstr "Llegeix-ne més"
@@ -70,6 +75,9 @@ msgstr "Entrada anterior"
msgid "Also available in:"
msgstr "També disponibles en:"
+msgid "Languages:"
+msgstr ""
+
msgid "Original site"
msgstr "Lloc original"
@@ -79,6 +87,9 @@ msgstr "Entrades anteriors"
msgid "Archive"
msgstr "Arxiu"
+msgid "Publication date"
+msgstr ""
+
msgid "Posted:"
msgstr "Publicat:"
@@ -90,3 +101,9 @@ msgstr ""
msgid "No posts found."
msgstr ""
+
+msgid "RSS feed"
+msgstr ""
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/cs.po b/translations/nikola.messages/cs.po
index d55d197..8d6bd1e 100644
--- a/translations/nikola.messages/cs.po
+++ b/translations/nikola.messages/cs.po
@@ -4,13 +4,15 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Ondřej Grover <ondrej.grover@gmail.com>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Czech (http://www.transifex.com/projects/p/nikola/language/cs/)\n"
"MIME-Version: 1.0\n"
@@ -34,6 +36,9 @@ msgstr "Kategorie"
msgid "Tags and Categories"
msgstr "Štítky a kategorie"
+msgid "Comments"
+msgstr ""
+
msgid "Read more"
msgstr "Číst dál"
@@ -69,6 +74,9 @@ msgstr "Předchozí příspěvek"
msgid "Also available in:"
msgstr "Dostupné také v"
+msgid "Languages:"
+msgstr ""
+
msgid "Original site"
msgstr "Původní stránka"
@@ -78,6 +86,9 @@ msgstr "Starší příspěvky"
msgid "Archive"
msgstr "Archiv"
+msgid "Publication date"
+msgstr ""
+
msgid "Posted:"
msgstr "Zveřejněno:"
@@ -89,3 +100,9 @@ msgstr ""
msgid "No posts found."
msgstr ""
+
+msgid "RSS feed"
+msgstr ""
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/de.po b/translations/nikola.messages/de.po
index dde07a9..8564bfb 100644
--- a/translations/nikola.messages/de.po
+++ b/translations/nikola.messages/de.po
@@ -4,21 +4,23 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Kwpolska <kwpolska@gmail.com>, 2013-2014
# Kwpolska <kwpolska@gmail.com>, 2013
# Kwpolska <kwpolska@gmail.com>, 2013
-# Niko <wenso@gmx.de>, 2013
+# Herr Amok <wenso@gmx.de>, 2013
# ralsina <ralsina@netmanagers.com.ar>, 2013
# ralsina <ralsina@netmanagers.com.ar>, 2013
# udono <udono@gmx.net>, 2013
# udono <udono@gmx.net>, 2013
-# Niko <wenso@gmx.de>, 2013
+# Herr Amok <wenso@gmx.de>, 2013
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:57+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: German (http://www.transifex.com/projects/p/nikola/language/de/)\n"
"MIME-Version: 1.0\n"
@@ -42,6 +44,9 @@ msgstr "Kategorien"
msgid "Tags and Categories"
msgstr "Tags und Kategorien"
+msgid "Comments"
+msgstr "Kommentare"
+
msgid "Read more"
msgstr "Weiterlesen"
@@ -77,6 +82,9 @@ msgstr "Vorheriger Eintrag"
msgid "Also available in:"
msgstr "Auch verfügbar in:"
+msgid "Languages:"
+msgstr "Sprachen:"
+
msgid "Original site"
msgstr "Original-Seite"
@@ -86,6 +94,9 @@ msgstr "Ältere Einträge"
msgid "Archive"
msgstr "Archiv"
+msgid "Publication date"
+msgstr "Veröffentlichungsdatum"
+
msgid "Posted:"
msgstr "Veröffentlicht:"
@@ -96,4 +107,10 @@ msgid "Nothing found."
msgstr "Nichts gefunden."
msgid "No posts found."
-msgstr "Keine einträge gefunden."
+msgstr "Keine Einträge gefunden."
+
+msgid "RSS feed"
+msgstr "RSS-Feed"
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/el.po b/translations/nikola.messages/el.po
index 6a4f393..41ba386 100644
--- a/translations/nikola.messages/el.po
+++ b/translations/nikola.messages/el.po
@@ -4,6 +4,8 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# pmav99 <otinanai90@gmail.com>, 2013
# pmav99 <otinanai90@gmail.com>, 2013
# ralsina <ralsina@netmanagers.com.ar>, 2013
@@ -13,7 +15,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Greek (http://www.transifex.com/projects/p/nikola/language/el/)\n"
"MIME-Version: 1.0\n"
@@ -37,6 +39,9 @@ msgstr "Κατηγορίες"
msgid "Tags and Categories"
msgstr "Ετικέτες και κατηγορίες"
+msgid "Comments"
+msgstr ""
+
msgid "Read more"
msgstr "Διαβάστε περισσότερα"
@@ -72,6 +77,9 @@ msgstr "Προηγούμενη ανάρτηση"
msgid "Also available in:"
msgstr "Διαθέσιμο και στα:"
+msgid "Languages:"
+msgstr ""
+
msgid "Original site"
msgstr "Ιστοσελίδα αρχικής ανάρτησης"
@@ -81,6 +89,9 @@ msgstr "Παλαιότερες αναρτήσεις"
msgid "Archive"
msgstr "Αρχείο"
+msgid "Publication date"
+msgstr ""
+
msgid "Posted:"
msgstr "Αναρτήθηκε:"
@@ -92,3 +103,9 @@ msgstr ""
msgid "No posts found."
msgstr ""
+
+msgid "RSS feed"
+msgstr ""
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/en.po b/translations/nikola.messages/en.po
index dd51ce3..e77d3ac 100644
--- a/translations/nikola.messages/en.po
+++ b/translations/nikola.messages/en.po
@@ -3,14 +3,17 @@
# This file is distributed under the same license as the Nikola package.
#
# Translators:
-# Roberto Alsina <ralsina@netmanagers.com.ar>, 2013.
+# Translators:
+# Translators:
+# ralsina <ralsina@netmanagers.com.ar>, 2013
+# ralsina <ralsina@netmanagers.com.ar>, 2013
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2013-03-15 15:29+0000\n"
-"Last-Translator: ralsina <ralsina@netmanagers.com.ar>\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
+"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -32,6 +35,9 @@ msgstr "Categories"
msgid "Tags and Categories"
msgstr "Tags and Categories"
+msgid "Comments"
+msgstr "Comments"
+
msgid "Read more"
msgstr "Read more"
@@ -50,7 +56,8 @@ msgstr "page %d"
msgid "Source"
msgstr "Source"
-#. Here your translation should not say English but the name of your language instead
+#. Here your translation should not say English but the name of your language
+#. instead
msgid "Read in English"
msgstr "Read in English"
@@ -66,6 +73,9 @@ msgstr "Previous post"
msgid "Also available in:"
msgstr "Also available in:"
+msgid "Languages:"
+msgstr "Languages:"
+
msgid "Original site"
msgstr "Original site"
@@ -75,6 +85,9 @@ msgstr "Older posts"
msgid "Archive"
msgstr "Archive"
+msgid "Publication date"
+msgstr "Publication date"
+
msgid "Posted:"
msgstr "Posted:"
@@ -86,3 +99,9 @@ msgstr "Nothing found."
msgid "No posts found."
msgstr "No posts found."
+
+msgid "RSS feed"
+msgstr "RSS feed"
+
+msgid "%d min remaining to read"
+msgstr "%d min remaining to read"
diff --git a/translations/nikola.messages/eo.po b/translations/nikola.messages/eo.po
index ee267de..8722c89 100644
--- a/translations/nikola.messages/eo.po
+++ b/translations/nikola.messages/eo.po
@@ -4,6 +4,8 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# David Paleino <d.paleino@gmail.com>, 2013
# David Paleino <d.paleino@gmail.com>, 2013
msgid ""
@@ -11,7 +13,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Esperanto (http://www.transifex.com/projects/p/nikola/language/eo/)\n"
"MIME-Version: 1.0\n"
@@ -35,6 +37,9 @@ msgstr "Kategorioj"
msgid "Tags and Categories"
msgstr "Etikedoj kaj Kategorioj"
+msgid "Comments"
+msgstr ""
+
msgid "Read more"
msgstr "Legu plu"
@@ -70,6 +75,9 @@ msgstr "Antaŭa artikolo"
msgid "Also available in:"
msgstr "Ankaŭ disponebla en:"
+msgid "Languages:"
+msgstr ""
+
msgid "Original site"
msgstr "Originala interretejo"
@@ -79,6 +87,9 @@ msgstr "Pli malnovaj artikoloj"
msgid "Archive"
msgstr "Arĥivo"
+msgid "Publication date"
+msgstr ""
+
msgid "Posted:"
msgstr "Skribita:"
@@ -90,3 +101,9 @@ msgstr ""
msgid "No posts found."
msgstr ""
+
+msgid "RSS feed"
+msgstr ""
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/es.po b/translations/nikola.messages/es.po
index 3650dd5..58bf6ee 100644
--- a/translations/nikola.messages/es.po
+++ b/translations/nikola.messages/es.po
@@ -4,15 +4,17 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# ralsina <ralsina@netmanagers.com.ar>, 2013
-# ralsina <ralsina@netmanagers.com.ar>, 2013
+# ralsina <ralsina@netmanagers.com.ar>, 2013-2014
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
-"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
+"PO-Revision-Date: 2014-04-20 16:45+0000\n"
+"Last-Translator: ralsina <ralsina@netmanagers.com.ar>\n"
"Language-Team: Spanish (http://www.transifex.com/projects/p/nikola/language/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -35,6 +37,9 @@ msgstr "Categorías"
msgid "Tags and Categories"
msgstr "Tags y Categorías"
+msgid "Comments"
+msgstr "Comentarios"
+
msgid "Read more"
msgstr "Leer más"
@@ -70,6 +75,9 @@ msgstr "Post anterior"
msgid "Also available in:"
msgstr "También disponible en:"
+msgid "Languages:"
+msgstr "Idiomas:"
+
msgid "Original site"
msgstr "Sitio original"
@@ -79,6 +87,9 @@ msgstr "Posts anteriores"
msgid "Archive"
msgstr "Archivo"
+msgid "Publication date"
+msgstr "Fecha de publicación"
+
msgid "Posted:"
msgstr "Publicado:"
@@ -86,7 +97,13 @@ msgid "Posts for {month} {year}"
msgstr "Posts de {month} {year}"
msgid "Nothing found."
-msgstr ""
+msgstr "No encontrado"
msgid "No posts found."
-msgstr ""
+msgstr "No se encontraron posts"
+
+msgid "RSS feed"
+msgstr "feed RSS"
+
+msgid "%d min remaining to read"
+msgstr "restan %d minutos"
diff --git a/translations/nikola.messages/et.po b/translations/nikola.messages/et.po
index 5f5faa5..2903258 100644
--- a/translations/nikola.messages/et.po
+++ b/translations/nikola.messages/et.po
@@ -4,6 +4,8 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Kwpolska <kwpolska@gmail.com>, 2014
# Kwpolska <kwpolska@gmail.com>, 2014
# Lauri Võsandi <lauri.vosandi@gmail.com>, 2013
@@ -12,7 +14,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Estonian (http://www.transifex.com/projects/p/nikola/language/et/)\n"
"MIME-Version: 1.0\n"
@@ -36,6 +38,9 @@ msgstr "Kategooriad"
msgid "Tags and Categories"
msgstr "Sildid ja kategooriad"
+msgid "Comments"
+msgstr ""
+
msgid "Read more"
msgstr "Loe veel"
@@ -71,6 +76,9 @@ msgstr "Eelmine postitus"
msgid "Also available in:"
msgstr "Saadaval ka:"
+msgid "Languages:"
+msgstr ""
+
msgid "Original site"
msgstr "Algallikas"
@@ -80,6 +88,9 @@ msgstr "Vanemad postitused"
msgid "Archive"
msgstr "Arhiiv"
+msgid "Publication date"
+msgstr ""
+
msgid "Posted:"
msgstr "Postitatud:"
@@ -91,3 +102,9 @@ msgstr ""
msgid "No posts found."
msgstr ""
+
+msgid "RSS feed"
+msgstr ""
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/eu.po b/translations/nikola.messages/eu.po
index c6803b4..a41ea99 100644
--- a/translations/nikola.messages/eu.po
+++ b/translations/nikola.messages/eu.po
@@ -4,6 +4,8 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# aitorp <aitorp@gmail.com>, 2013
# aitorp <aitorp@gmail.com>, 2013
msgid ""
@@ -11,7 +13,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Basque (http://www.transifex.com/projects/p/nikola/language/eu/)\n"
"MIME-Version: 1.0\n"
@@ -35,6 +37,9 @@ msgstr "Kategoriak"
msgid "Tags and Categories"
msgstr "Etiketak eta Kategoriak"
+msgid "Comments"
+msgstr ""
+
msgid "Read more"
msgstr "Irakurri gehiago"
@@ -70,6 +75,9 @@ msgstr "Aurreko posta"
msgid "Also available in:"
msgstr "Eskuragarria hemen ere:"
+msgid "Languages:"
+msgstr ""
+
msgid "Original site"
msgstr "Jatorrizko orria"
@@ -79,6 +87,9 @@ msgstr "Post zaharrenak"
msgid "Archive"
msgstr "Artxiboa"
+msgid "Publication date"
+msgstr ""
+
msgid "Posted:"
msgstr "Argitaratuta:"
@@ -90,3 +101,9 @@ msgstr ""
msgid "No posts found."
msgstr ""
+
+msgid "RSS feed"
+msgstr ""
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/fa.po b/translations/nikola.messages/fa.po
index a6c4e33..eb39d42 100644
--- a/translations/nikola.messages/fa.po
+++ b/translations/nikola.messages/fa.po
@@ -4,6 +4,9 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
+# Hossein Rayeshman <rayeshman@gmail.com>, 2014
# Shahinism <ishahinism@gmail.com>, 2013
# sazary <soroosh@azary.ir>, 2013
# Shahinism <ishahinism@gmail.com>, 2013
@@ -13,7 +16,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Persian (http://www.transifex.com/projects/p/nikola/language/fa/)\n"
"MIME-Version: 1.0\n"
@@ -37,6 +40,9 @@ msgstr "دسته‌ها"
msgid "Tags and Categories"
msgstr "برچسب‌ها و دسته‌ها"
+msgid "Comments"
+msgstr "دیدگاه‌‌‌ها"
+
msgid "Read more"
msgstr "بیشتر بخوانید"
@@ -50,7 +56,7 @@ msgid "old posts, page %d"
msgstr "صفحهٔ ارسال‌های قدیمی %d"
msgid "page %d"
-msgstr ""
+msgstr "برگه %d"
msgid "Source"
msgstr "منبع"
@@ -72,6 +78,9 @@ msgstr "ارسال پیشین"
msgid "Also available in:"
msgstr "همچنین قابل دسترس از:"
+msgid "Languages:"
+msgstr "زبان‌‌ها:"
+
msgid "Original site"
msgstr "سایت اصلی"
@@ -81,6 +90,9 @@ msgstr "پست‌های قدیمی‌تر"
msgid "Archive"
msgstr "آرشیو"
+msgid "Publication date"
+msgstr "تاریخ انتشار"
+
msgid "Posted:"
msgstr "ارسال شده:"
@@ -88,7 +100,13 @@ msgid "Posts for {month} {year}"
msgstr "ارسال برای {month} {year}"
msgid "Nothing found."
-msgstr ""
+msgstr "هیچ‌چیزی پیدا نشد."
msgid "No posts found."
+msgstr "هیچ پستی پیدا نشد."
+
+msgid "RSS feed"
+msgstr "خوراک"
+
+msgid "%d min remaining to read"
msgstr ""
diff --git a/translations/nikola.messages/fi.po b/translations/nikola.messages/fi.po
index 6ce903f..b52463b 100644
--- a/translations/nikola.messages/fi.po
+++ b/translations/nikola.messages/fi.po
@@ -4,15 +4,17 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Eero Kari <eero.kari@gmail.com>, 2013
-# Eero Kari <eero.kari@gmail.com>, 2013
+# Eero Kari <eero.kari@gmail.com>, 2013-2014
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
-"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
+"PO-Revision-Date: 2014-05-31 08:51+0000\n"
+"Last-Translator: Eero Kari <eero.kari@gmail.com>\n"
"Language-Team: Finnish (http://www.transifex.com/projects/p/nikola/language/fi/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -35,6 +37,9 @@ msgstr "Kategoriat"
msgid "Tags and Categories"
msgstr "Tagit ja kategoriat"
+msgid "Comments"
+msgstr "Kommentit"
+
msgid "Read more"
msgstr "Lue lisää"
@@ -45,7 +50,7 @@ msgid "Next post"
msgstr "Seuraava postaus"
msgid "old posts, page %d"
-msgstr "vanhojen postauksien, sivu %d"
+msgstr "vanhoja postauksia, sivu %d"
msgid "page %d"
msgstr "sivu %d"
@@ -70,6 +75,9 @@ msgstr "Vanhempia postauksia"
msgid "Also available in:"
msgstr "Saatavilla myös:"
+msgid "Languages:"
+msgstr "Kielet:"
+
msgid "Original site"
msgstr "Alkuperäinen sivusto"
@@ -79,6 +87,9 @@ msgstr "Vanhempia postauksia"
msgid "Archive"
msgstr "Arkisto"
+msgid "Publication date"
+msgstr "Julkaisupäivämäärä"
+
msgid "Posted:"
msgstr "Postattu:"
@@ -86,7 +97,13 @@ msgid "Posts for {month} {year}"
msgstr "Postauksia ajalle {month} {year}"
msgid "Nothing found."
-msgstr ""
+msgstr "Ei hakutuloksia."
msgid "No posts found."
+msgstr "Postauksia ei löytynyt."
+
+msgid "RSS feed"
+msgstr "RSS syöte"
+
+msgid "%d min remaining to read"
msgstr ""
diff --git a/translations/nikola.messages/fr.po b/translations/nikola.messages/fr.po
index 8b68987..191d315 100644
--- a/translations/nikola.messages/fr.po
+++ b/translations/nikola.messages/fr.po
@@ -4,8 +4,11 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# JohnPreston <john.mille78@gmail.com>, 2014
# JohnPreston <john.mille78@gmail.com>, 2014
+# pabluk <pablo@seminar.io>, 2014
# pabluk <pablo@seminar.io>, 2013
# pabluk <pablo@seminar.io>, 2013
# pabluk <pablo@seminar.io>, 2013
@@ -16,7 +19,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: French (http://www.transifex.com/projects/p/nikola/language/fr/)\n"
"MIME-Version: 1.0\n"
@@ -40,6 +43,9 @@ msgstr "Catégories"
msgid "Tags and Categories"
msgstr "Étiquettes et catégories"
+msgid "Comments"
+msgstr "Commentaires"
+
msgid "Read more"
msgstr "Lire la suite"
@@ -75,6 +81,9 @@ msgstr "Article précédent"
msgid "Also available in:"
msgstr "Egalement disponible en:"
+msgid "Languages:"
+msgstr "Langues:"
+
msgid "Original site"
msgstr "Site d'origine"
@@ -84,6 +93,9 @@ msgstr "Anciens articles"
msgid "Archive"
msgstr "Archives"
+msgid "Publication date"
+msgstr "Date de publication"
+
msgid "Posted:"
msgstr "Publié:"
@@ -91,7 +103,13 @@ msgid "Posts for {month} {year}"
msgstr "Articles de {month} {year}"
msgid "Nothing found."
-msgstr ""
+msgstr "Pas de résultats."
msgid "No posts found."
+msgstr "Pas de billets."
+
+msgid "RSS feed"
+msgstr "Flux RSS"
+
+msgid "%d min remaining to read"
msgstr ""
diff --git a/translations/nikola.messages/hi.po b/translations/nikola.messages/hi.po
index d464f99..d44ebb7 100644
--- a/translations/nikola.messages/hi.po
+++ b/translations/nikola.messages/hi.po
@@ -4,13 +4,15 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# seanpue <a@seanpue.com>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Hindi (http://www.transifex.com/projects/p/nikola/language/hi/)\n"
"MIME-Version: 1.0\n"
@@ -34,6 +36,9 @@ msgstr "श्रेणियाँ"
msgid "Tags and Categories"
msgstr "टैग्स और श्रेणियाँ"
+msgid "Comments"
+msgstr ""
+
msgid "Read more"
msgstr "और पढ़िए"
@@ -69,6 +74,9 @@ msgstr "पिछली पोस्ट"
msgid "Also available in:"
msgstr "उपलब्ध भाषाएँ:"
+msgid "Languages:"
+msgstr ""
+
msgid "Original site"
msgstr "असली साइट"
@@ -78,6 +86,9 @@ msgstr "पुरानी पोस्टें"
msgid "Archive"
msgstr "आर्काइव"
+msgid "Publication date"
+msgstr ""
+
msgid "Posted:"
msgstr "पोस्टेड:"
@@ -89,3 +100,9 @@ msgstr ""
msgid "No posts found."
msgstr ""
+
+msgid "RSS feed"
+msgstr ""
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/hr.po b/translations/nikola.messages/hr.po
index c2bae75..4bed477 100644
--- a/translations/nikola.messages/hr.po
+++ b/translations/nikola.messages/hr.po
@@ -4,14 +4,16 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# tty, 2013
-# tty, 2013
+# tty, 2013-2014
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Croatian (http://www.transifex.com/projects/p/nikola/language/hr/)\n"
"MIME-Version: 1.0\n"
@@ -35,6 +37,9 @@ msgstr "Kategorije"
msgid "Tags and Categories"
msgstr "Tagovi i kategorije"
+msgid "Comments"
+msgstr "Komentari"
+
msgid "Read more"
msgstr "Čitaj dalje"
@@ -70,6 +75,9 @@ msgstr "Prethodni post"
msgid "Also available in:"
msgstr "Također dostupno i u:"
+msgid "Languages:"
+msgstr "Jezici:"
+
msgid "Original site"
msgstr "Izvorna stranica"
@@ -79,6 +87,9 @@ msgstr "Stariji postovi"
msgid "Archive"
msgstr "Arhiva"
+msgid "Publication date"
+msgstr "Nadnevak objave"
+
msgid "Posted:"
msgstr "Objavljeno:"
@@ -86,7 +97,13 @@ msgid "Posts for {month} {year}"
msgstr "Postovi za {month} {year}"
msgid "Nothing found."
-msgstr ""
+msgstr "Nema ničeg."
msgid "No posts found."
+msgstr "Nema postova."
+
+msgid "RSS feed"
+msgstr "RSS kanal"
+
+msgid "%d min remaining to read"
msgstr ""
diff --git a/translations/nikola.messages/it.po b/translations/nikola.messages/it.po
index 1c03e0b..aa44143 100644
--- a/translations/nikola.messages/it.po
+++ b/translations/nikola.messages/it.po
@@ -4,16 +4,20 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Alessandro Pisa <alessandro.pisa@gmail.com>, 2013
+# Kwpolska <kwpolska@gmail.com>, 2014
# David Paleino <d.paleino@gmail.com>, 2013
# ralsina <ralsina@netmanagers.com.ar>, 2013
# ralsina <ralsina@netmanagers.com.ar>, 2013
+# Stefano Karapetsas <stefano@karapetsas.com>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-05-18 12:44+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.com/projects/p/nikola/language/it/)\n"
"MIME-Version: 1.0\n"
@@ -37,8 +41,11 @@ msgstr "Categorie"
msgid "Tags and Categories"
msgstr "Tags e Categorie"
+msgid "Comments"
+msgstr "Commenti"
+
msgid "Read more"
-msgstr "Espandi"
+msgstr "Continua la lettura"
msgid "Posts about %s"
msgstr "Articoli su %s"
@@ -72,6 +79,9 @@ msgstr "Articolo precedente"
msgid "Also available in:"
msgstr "Anche disponibile in:"
+msgid "Languages:"
+msgstr "Lingue:"
+
msgid "Original site"
msgstr "Sito originale"
@@ -81,6 +91,9 @@ msgstr "Articoli precedenti"
msgid "Archive"
msgstr "Archivio"
+msgid "Publication date"
+msgstr "Data di pubblicazione"
+
msgid "Posted:"
msgstr "Pubblicato:"
@@ -88,7 +101,13 @@ msgid "Posts for {month} {year}"
msgstr "Articoli per {month} {year}"
msgid "Nothing found."
-msgstr ""
+msgstr "Non trovato."
msgid "No posts found."
-msgstr ""
+msgstr "Nessun articolo trovato."
+
+msgid "RSS feed"
+msgstr "Flusso RSS"
+
+msgid "%d min remaining to read"
+msgstr "ancora %d minuti"
diff --git a/translations/nikola.messages/ja.po b/translations/nikola.messages/ja.po
index 7e0eaa7..31c0212 100644
--- a/translations/nikola.messages/ja.po
+++ b/translations/nikola.messages/ja.po
@@ -4,8 +4,11 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Kwpolska <kwpolska@gmail.com>, 2013
# Kwpolska <kwpolska@gmail.com>, 2013
+# mikako, 2014
# quoth <4wordextinguisher@gmail.com>, 2013
# ralsina <ralsina@netmanagers.com.ar>, 2013
# ralsina <ralsina@netmanagers.com.ar>, 2013
@@ -15,7 +18,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Japanese (http://www.transifex.com/projects/p/nikola/language/ja/)\n"
"MIME-Version: 1.0\n"
@@ -39,6 +42,9 @@ msgstr "カテゴリー"
msgid "Tags and Categories"
msgstr "タグとカテゴリー"
+msgid "Comments"
+msgstr "コメント"
+
msgid "Read more"
msgstr "続きを読む"
@@ -52,7 +58,7 @@ msgid "old posts, page %d"
msgstr "前の記事 %dページ目"
msgid "page %d"
-msgstr ""
+msgstr "ページ %d"
msgid "Source"
msgstr "ソース"
@@ -74,6 +80,9 @@ msgstr "前の記事"
msgid "Also available in:"
msgstr "他の言語で読む:"
+msgid "Languages:"
+msgstr "言語 :"
+
msgid "Original site"
msgstr "元のサイト"
@@ -83,6 +92,9 @@ msgstr "過去の記事"
msgid "Archive"
msgstr "過去の記事"
+msgid "Publication date"
+msgstr "投稿日"
+
msgid "Posted:"
msgstr "投稿日時:"
@@ -90,7 +102,13 @@ msgid "Posts for {month} {year}"
msgstr "{year}年{month}月の記事"
msgid "Nothing found."
-msgstr ""
+msgstr "なにも見つかりませんでした"
msgid "No posts found."
+msgstr "記事はありません"
+
+msgid "RSS feed"
+msgstr "RSS フィード"
+
+msgid "%d min remaining to read"
msgstr ""
diff --git a/translations/nikola.messages/nb.po b/translations/nikola.messages/nb.po
index 8ac9ae4..c75621c 100644
--- a/translations/nikola.messages/nb.po
+++ b/translations/nikola.messages/nb.po
@@ -4,13 +4,15 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Daniel <i18n@daniel.priv.no>, 2013
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Norwegian Bokmål (http://www.transifex.com/projects/p/nikola/language/nb/)\n"
"MIME-Version: 1.0\n"
@@ -34,6 +36,9 @@ msgstr "Kategorier"
msgid "Tags and Categories"
msgstr "Merker og kategorier"
+msgid "Comments"
+msgstr ""
+
msgid "Read more"
msgstr "Les mer"
@@ -69,6 +74,9 @@ msgstr "Forrige innlegg"
msgid "Also available in:"
msgstr "Også tilgjengelig på:"
+msgid "Languages:"
+msgstr ""
+
msgid "Original site"
msgstr "Opprinnelig side"
@@ -78,6 +86,9 @@ msgstr "Eldre innlegg"
msgid "Archive"
msgstr "Arkiv"
+msgid "Publication date"
+msgstr ""
+
msgid "Posted:"
msgstr "Publisert:"
@@ -89,3 +100,9 @@ msgstr ""
msgid "No posts found."
msgstr ""
+
+msgid "RSS feed"
+msgstr ""
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/nl.po b/translations/nikola.messages/nl.po
index 637dd5e..7d01718 100644
--- a/translations/nikola.messages/nl.po
+++ b/translations/nikola.messages/nl.po
@@ -4,6 +4,8 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Joes <joes@staalkemade.net>, 2013
# Joes <joes@staalkemade.net>, 2013-2014
msgid ""
@@ -11,8 +13,8 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
-"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
+"PO-Revision-Date: 2014-04-22 14:35+0000\n"
+"Last-Translator: Joes <joes@staalkemade.net>\n"
"Language-Team: Dutch (http://www.transifex.com/projects/p/nikola/language/nl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -35,6 +37,9 @@ msgstr "Categorieën"
msgid "Tags and Categories"
msgstr "Tags en Categorieën"
+msgid "Comments"
+msgstr "Commentaar"
+
msgid "Read more"
msgstr "Lees verder"
@@ -70,6 +75,9 @@ msgstr "Vorig bericht"
msgid "Also available in:"
msgstr "Ook beschikbaar in:"
+msgid "Languages:"
+msgstr "Talen:"
+
msgid "Original site"
msgstr "Originele site"
@@ -79,6 +87,9 @@ msgstr "Oudere berichten"
msgid "Archive"
msgstr "Archief"
+msgid "Publication date"
+msgstr "Publicatiedatum"
+
msgid "Posted:"
msgstr "Geplaatst:"
@@ -86,7 +97,13 @@ msgid "Posts for {month} {year}"
msgstr "Berichten voor {month} {year}"
msgid "Nothing found."
-msgstr ""
+msgstr "Niets gevonden."
msgid "No posts found."
-msgstr ""
+msgstr "Geen berichten gevonden."
+
+msgid "RSS feed"
+msgstr "RSS-feed"
+
+msgid "%d min remaining to read"
+msgstr "%d min resterende leestijd "
diff --git a/translations/nikola.messages/pl.po b/translations/nikola.messages/pl.po
index a9ee5d3..ab7fbbe 100644
--- a/translations/nikola.messages/pl.po
+++ b/translations/nikola.messages/pl.po
@@ -4,6 +4,8 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Kwpolska <kwpolska@gmail.com>, 2013-2014
# Kwpolska <kwpolska@gmail.com>, 2013
# Kwpolska <kwpolska@gmail.com>, 2013
@@ -14,7 +16,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:48+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Polish (http://www.transifex.com/projects/p/nikola/language/pl/)\n"
"MIME-Version: 1.0\n"
@@ -38,6 +40,9 @@ msgstr "Kategorie"
msgid "Tags and Categories"
msgstr "Tagi i Kategorie"
+msgid "Comments"
+msgstr "Komentarze"
+
msgid "Read more"
msgstr "Czytaj więcej"
@@ -73,6 +78,9 @@ msgstr "Poprzedni post"
msgid "Also available in:"
msgstr "Również dostępny w językach:"
+msgid "Languages:"
+msgstr "Języki:"
+
msgid "Original site"
msgstr "Oryginalna strona"
@@ -82,6 +90,9 @@ msgstr "Starsze posty"
msgid "Archive"
msgstr "Archiwum"
+msgid "Publication date"
+msgstr "Data publikacji"
+
msgid "Posted:"
msgstr "Opublikowano:"
@@ -93,3 +104,9 @@ msgstr "Nic nie znaleziono."
msgid "No posts found."
msgstr "Nie znaleziono żadnych postów."
+
+msgid "RSS feed"
+msgstr "Kanał RSS"
+
+msgid "%d min remaining to read"
+msgstr "zostało %d minut czytania"
diff --git a/translations/nikola.messages/pt_BR.po b/translations/nikola.messages/pt_BR.po
index 79239d9..6821f88 100644
--- a/translations/nikola.messages/pt_BR.po
+++ b/translations/nikola.messages/pt_BR.po
@@ -4,6 +4,9 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
+# Thiago Cangussu <cangussu.thg@gmail.com>, 2014
# schettino72 <schettino72@gmail.com>, 2013
# Kwpolska <kwpolska@gmail.com>, 2013
# Kwpolska <kwpolska@gmail.com>, 2013
@@ -15,8 +18,8 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
-"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
+"PO-Revision-Date: 2014-05-05 19:42+0000\n"
+"Last-Translator: Thiago Cangussu <cangussu.thg@gmail.com>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/nikola/language/pt_BR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -39,6 +42,9 @@ msgstr "Categorias"
msgid "Tags and Categories"
msgstr "Tags e Categorias"
+msgid "Comments"
+msgstr "Comentários"
+
msgid "Read more"
msgstr "Leia mais"
@@ -74,6 +80,9 @@ msgstr "Post anterior"
msgid "Also available in:"
msgstr "Também disponível em:"
+msgid "Languages:"
+msgstr "Idiomas:"
+
msgid "Original site"
msgstr "Site original"
@@ -83,6 +92,9 @@ msgstr "Posts mais antigos"
msgid "Archive"
msgstr "Arquivo"
+msgid "Publication date"
+msgstr "Data de publicação"
+
msgid "Posted:"
msgstr "Publicado:"
@@ -90,7 +102,13 @@ msgid "Posts for {month} {year}"
msgstr "Posts de {month} {year}"
msgid "Nothing found."
-msgstr ""
+msgstr "Nada encontrado."
msgid "No posts found."
-msgstr ""
+msgstr "Nenhum tópico encontrado."
+
+msgid "RSS feed"
+msgstr "Feed RSS"
+
+msgid "%d min remaining to read"
+msgstr "%d mín restante para leitura"
diff --git a/translations/nikola.messages/ru.po b/translations/nikola.messages/ru.po
index b682307..062d40b 100644
--- a/translations/nikola.messages/ru.po
+++ b/translations/nikola.messages/ru.po
@@ -4,6 +4,9 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
+# Dmitry Paskal <paskal.07@gmail.com>, 2014
# m.arnold <lwarxx@gmail.com>, 2013
# m.arnold <lwarxx@gmail.com>, 2013
# ralsina <ralsina@netmanagers.com.ar>, 2013
@@ -13,8 +16,8 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
-"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
+"PO-Revision-Date: 2014-05-31 18:01+0000\n"
+"Last-Translator: Dmitry Paskal <paskal.07@gmail.com>\n"
"Language-Team: Russian (http://www.transifex.com/projects/p/nikola/language/ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -37,6 +40,9 @@ msgstr "Категории"
msgid "Tags and Categories"
msgstr "Тэги и категории"
+msgid "Comments"
+msgstr "Комментарии"
+
msgid "Read more"
msgstr "Читать далее"
@@ -72,6 +78,9 @@ msgstr "Предыдущая запись"
msgid "Also available in:"
msgstr "Также доступно на:"
+msgid "Languages:"
+msgstr "Языки:"
+
msgid "Original site"
msgstr "Оригинальный сайт"
@@ -81,6 +90,9 @@ msgstr "Старые записи"
msgid "Archive"
msgstr "Архив"
+msgid "Publication date"
+msgstr "Дата опубликования"
+
msgid "Posted:"
msgstr "Опубликовано:"
@@ -88,7 +100,13 @@ msgid "Posts for {month} {year}"
msgstr "Записи за {month} {year}"
msgid "Nothing found."
-msgstr ""
+msgstr "Ничего не найдено."
msgid "No posts found."
-msgstr ""
+msgstr "Записей не найдено."
+
+msgid "RSS feed"
+msgstr "RSS лента"
+
+msgid "%d min remaining to read"
+msgstr "%d минут чтения осталось"
diff --git a/translations/nikola.messages/sk.po b/translations/nikola.messages/sk.po
new file mode 100644
index 0000000..ecd0d4f
--- /dev/null
+++ b/translations/nikola.messages/sk.po
@@ -0,0 +1,108 @@
+# Messages in Nikola
+# Copyright (C) 2012-2013
+# This file is distributed under the same license as the Nikola package.
+#
+# Translators:
+# Translators:
+# Translators:
+# Translators:
+# Tomáš Prékop <info@pwn.sk>, 2014
+msgid ""
+msgstr ""
+"Project-Id-Version: Nikola\n"
+"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
+"POT-Creation-Date: 2013-03-15 12:24-0300\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
+"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
+"Language-Team: Slovak (http://www.transifex.com/projects/p/nikola/language/sk/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: sk\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+
+msgid "More posts about %s"
+msgstr "Viac príspevkov o %s"
+
+msgid "LANGUAGE"
+msgstr "Slovenčina"
+
+msgid "Tags"
+msgstr "Štítky"
+
+msgid "Categories"
+msgstr "Kategórie"
+
+msgid "Tags and Categories"
+msgstr "Štítky a kategórie"
+
+msgid "Comments"
+msgstr "Komentáre"
+
+msgid "Read more"
+msgstr "Čítať ďalej"
+
+msgid "Posts about %s"
+msgstr "Príspevky o %s"
+
+msgid "Next post"
+msgstr "Nasledujúci príspevok"
+
+msgid "old posts, page %d"
+msgstr "staré príspevky, strana %d"
+
+msgid "page %d"
+msgstr "stránka %d"
+
+msgid "Source"
+msgstr "Zdroj"
+
+#. Here your translation should not say English but the name of your language
+#. instead
+msgid "Read in English"
+msgstr "Čítať v slovenčine"
+
+msgid "Posts for year %s"
+msgstr "Príspevky z roku %s"
+
+msgid "Newer posts"
+msgstr "Novšie príspevky"
+
+msgid "Previous post"
+msgstr "Predchádzajúci príspevok"
+
+msgid "Also available in:"
+msgstr "Tiež dostupné v:"
+
+msgid "Languages:"
+msgstr "Jazyky:"
+
+msgid "Original site"
+msgstr "Pôvodná stránka"
+
+msgid "Older posts"
+msgstr "Staršie príspevky"
+
+msgid "Archive"
+msgstr "Archív"
+
+msgid "Publication date"
+msgstr "Dátum zverejnenia"
+
+msgid "Posted:"
+msgstr "Zverejnené:"
+
+msgid "Posts for {month} {year}"
+msgstr "Príspevky za mesiac {month} z roku {year}"
+
+msgid "Nothing found."
+msgstr "Nič nenájdené."
+
+msgid "No posts found."
+msgstr "Žiadne príspevky nenájdené"
+
+msgid "RSS feed"
+msgstr "RSS kanál"
+
+msgid "%d min remaining to read"
+msgstr ""
diff --git a/translations/nikola.messages/sl.po b/translations/nikola.messages/sl.po
index 50a0a2f..4d29e24 100644
--- a/translations/nikola.messages/sl.po
+++ b/translations/nikola.messages/sl.po
@@ -4,6 +4,8 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Venčeslav Vezjak <vezjakv@gmail.com>, 2013
# Venčeslav Vezjak <vezjakv@gmail.com>, 2013-2014
msgid ""
@@ -11,8 +13,8 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
-"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
+"PO-Revision-Date: 2014-04-18 08:02+0000\n"
+"Last-Translator: Venčeslav Vezjak <vezjakv@gmail.com>\n"
"Language-Team: Slovenian (http://www.transifex.com/projects/p/nikola/language/sl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -35,6 +37,9 @@ msgstr "Kategorije"
msgid "Tags and Categories"
msgstr "Značke in kategorije"
+msgid "Comments"
+msgstr "Komentarji"
+
msgid "Read more"
msgstr "Več o tem"
@@ -70,6 +75,9 @@ msgstr "Prejšnja objava"
msgid "Also available in:"
msgstr "Na voljo tudi v:"
+msgid "Languages:"
+msgstr "Jeziki:"
+
msgid "Original site"
msgstr "Izvorna spletna stran"
@@ -79,6 +87,9 @@ msgstr "Starejše objave"
msgid "Archive"
msgstr "Arhiv"
+msgid "Publication date"
+msgstr "Datum objave"
+
msgid "Posted:"
msgstr "Objavljeno:"
@@ -86,7 +97,13 @@ msgid "Posts for {month} {year}"
msgstr "Objave za {month} {year}"
msgid "Nothing found."
-msgstr ""
+msgstr "Brez zadetkov."
msgid "No posts found."
-msgstr ""
+msgstr "Ni najdenih objav."
+
+msgid "RSS feed"
+msgstr "vir RSS"
+
+msgid "%d min remaining to read"
+msgstr "za prebrati preostalo še %d min"
diff --git a/translations/nikola.messages/tr_TR.po b/translations/nikola.messages/tr.po
index 0afcbfa..3fff1de 100644
--- a/translations/nikola.messages/tr_TR.po
+++ b/translations/nikola.messages/tr.po
@@ -4,22 +4,24 @@
#
# Translators:
# Translators:
-# Batuhan Büyükgüzel <bbuyukguzel@gmail.com>, 2013
-# Caner BAŞARAN <basaran.caner@gmail.com>, 2013
+# Translators:
+# Translators:
+# Batuhan Büyükgüzel <bbuyukguzel@gmail.com>, 2013-2014
+# Caner BAŞARAN <basaran.caner@gmail.com>, 2014
# Caner BAŞARAN <basaran.caner@gmail.com>, 2013
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
-"Language-Team: Turkish (Turkey) (http://www.transifex.com/projects/p/nikola/language/tr_TR/)\n"
+"Language-Team: Turkish (http://www.transifex.com/projects/p/nikola/language/tr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Language: tr_TR\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
+"Language: tr\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
msgid "More posts about %s"
msgstr "%s ilgili diğer yazılar"
@@ -36,6 +38,9 @@ msgstr "Kategoriler"
msgid "Tags and Categories"
msgstr "Etiketler ve Kategoriler"
+msgid "Comments"
+msgstr "Yorumlar"
+
msgid "Read more"
msgstr "Devamını oku"
@@ -71,6 +76,9 @@ msgstr "Önceki yazı"
msgid "Also available in:"
msgstr "Şu dilde de mevcut:"
+msgid "Languages:"
+msgstr "Diller:"
+
msgid "Original site"
msgstr "Orjinal web sayfası"
@@ -80,6 +88,9 @@ msgstr "Daha eski yazılar"
msgid "Archive"
msgstr "Arşiv"
+msgid "Publication date"
+msgstr "Yayınlanma tarihi"
+
msgid "Posted:"
msgstr "Yayın tarihi:"
@@ -87,7 +98,13 @@ msgid "Posts for {month} {year}"
msgstr "{month} {year} göre yazılar"
msgid "Nothing found."
-msgstr ""
+msgstr "Hiçbir şey bulunamadı."
msgid "No posts found."
+msgstr "Yazı bulunamadı."
+
+msgid "RSS feed"
+msgstr "RSS kaynağı"
+
+msgid "%d min remaining to read"
msgstr ""
diff --git a/translations/nikola.messages/ur.po b/translations/nikola.messages/ur.po
index b70478a..fbe5301 100644
--- a/translations/nikola.messages/ur.po
+++ b/translations/nikola.messages/ur.po
@@ -4,17 +4,19 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# seanpue <a@seanpue.com>, 2014
# saadat, 2013
-# saadat <nastaliq@gmail.com>, 2013
+# saadat <nastaliq@gmail.com>, 2013-2014
# saadat <nastaliq@gmail.com>, 2013
msgid ""
msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
-"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
+"PO-Revision-Date: 2014-04-27 07:36+0000\n"
+"Last-Translator: saadat <nastaliq@gmail.com>\n"
"Language-Team: Urdu (http://www.transifex.com/projects/p/nikola/language/ur/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -37,6 +39,9 @@ msgstr "زمرے"
msgid "Tags and Categories"
msgstr "ٹیگز اور زمرے"
+msgid "Comments"
+msgstr "تبصرے"
+
msgid "Read more"
msgstr "مزید پڑھیے"
@@ -72,6 +77,9 @@ msgstr "پچھلی تحریر"
msgid "Also available in:"
msgstr "ان زبانوں میں بھی دستیاب:"
+msgid "Languages:"
+msgstr "زبانیں:"
+
msgid "Original site"
msgstr "اصلی سائٹ"
@@ -81,6 +89,9 @@ msgstr "پرانی تحاریر"
msgid "Archive"
msgstr "آرکائیو"
+msgid "Publication date"
+msgstr "تاریخِ اشاعت"
+
msgid "Posted:"
msgstr "اشاعت:"
@@ -88,7 +99,13 @@ msgid "Posts for {month} {year}"
msgstr "{month} {year} کی تحاریر"
msgid "Nothing found."
-msgstr ""
+msgstr "کچھ نہیں مل سکا۔"
msgid "No posts found."
-msgstr ""
+msgstr "کوئی تحریر نہیں مل سکی۔"
+
+msgid "RSS feed"
+msgstr "آر ایس ایس فیڈ"
+
+msgid "%d min remaining to read"
+msgstr "%d منٹ کا مطالعہ باقی"
diff --git a/translations/nikola.messages/zh_CN.po b/translations/nikola.messages/zh_CN.po
index ed466d2..1c6622d 100644
--- a/translations/nikola.messages/zh_CN.po
+++ b/translations/nikola.messages/zh_CN.po
@@ -4,6 +4,8 @@
#
# Translators:
# Translators:
+# Translators:
+# Translators:
# Christopher Meng <cickumqt@gmail.com>, 2013
# kadefor <kadefor@gmail.com>, 2013
# kadefor <kadefor@gmail.com>, 2013
@@ -14,7 +16,7 @@ msgstr ""
"Project-Id-Version: Nikola\n"
"Report-Msgid-Bugs-To: ralsina@netmanagers.com.ar\n"
"POT-Creation-Date: 2013-03-15 12:24-0300\n"
-"PO-Revision-Date: 2014-02-09 16:56+0000\n"
+"PO-Revision-Date: 2014-04-17 14:46+0000\n"
"Last-Translator: Kwpolska <kwpolska@gmail.com>\n"
"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/nikola/language/zh_CN/)\n"
"MIME-Version: 1.0\n"
@@ -38,6 +40,9 @@ msgstr "分类"
msgid "Tags and Categories"
msgstr "标签和分类"
+msgid "Comments"
+msgstr ""
+
msgid "Read more"
msgstr "更多"
@@ -73,6 +78,9 @@ msgstr "前一篇"
msgid "Also available in:"
msgstr "其他语言版本:"
+msgid "Languages:"
+msgstr ""
+
msgid "Original site"
msgstr "原文地址"
@@ -82,6 +90,9 @@ msgstr "旧一篇"
msgid "Archive"
msgstr "文章存档"
+msgid "Publication date"
+msgstr ""
+
msgid "Posted:"
msgstr "发表于:"
@@ -93,3 +104,9 @@ msgstr ""
msgid "No posts found."
msgstr ""
+
+msgid "RSS feed"
+msgstr ""
+
+msgid "%d min remaining to read"
+msgstr ""